]> granicus.if.org Git - postgresql/blob - src/backend/catalog/namespace.c
Add routines in namespace.c to determine whether objects are visible
[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-2001, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  * IDENTIFICATION
16  *        $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.17 2002/05/01 23:06:41 tgl Exp $
17  *
18  *-------------------------------------------------------------------------
19  */
20 #include "postgres.h"
21
22 #include "access/heapam.h"
23 #include "access/xact.h"
24 #include "catalog/catalog.h"
25 #include "catalog/catname.h"
26 #include "catalog/heap.h"
27 #include "catalog/namespace.h"
28 #include "catalog/pg_inherits.h"
29 #include "catalog/pg_namespace.h"
30 #include "catalog/pg_opclass.h"
31 #include "catalog/pg_operator.h"
32 #include "catalog/pg_proc.h"
33 #include "catalog/pg_shadow.h"
34 #include "catalog/pg_type.h"
35 #include "lib/stringinfo.h"
36 #include "miscadmin.h"
37 #include "nodes/makefuncs.h"
38 #include "storage/backendid.h"
39 #include "utils/acl.h"
40 #include "utils/builtins.h"
41 #include "utils/catcache.h"
42 #include "utils/fmgroids.h"
43 #include "utils/guc.h"
44 #include "utils/inval.h"
45 #include "utils/lsyscache.h"
46 #include "utils/syscache.h"
47
48
49 /*
50  * The namespace search path is a possibly-empty list of namespace OIDs.
51  * In addition to the explicit list, the TEMP table namespace is always
52  * implicitly searched first (if it's been initialized).  Also, the system
53  * catalog namespace is always searched.  If the system namespace is
54  * explicitly present in the path then it will be searched in the specified
55  * order; otherwise it will be searched after TEMP tables and *before* the
56  * explicit list.  (It might seem that the system namespace should be
57  * implicitly last, but this behavior appears to be required by SQL99.
58  * Also, this provides a way to search the system namespace first without
59  * thereby making it the default creation target namespace.)
60  *
61  * The default creation target namespace is kept equal to the first element
62  * of the (explicit) list.  If the list is empty, there is no default target.
63  *
64  * In bootstrap mode, the search path is set equal to 'pg_catalog', so that
65  * the system namespace is the only one searched or inserted into.
66  * The initdb script is also careful to set search_path to 'pg_catalog' for
67  * its post-bootstrap standalone backend runs.  Otherwise the default search
68  * path is determined by GUC.  The factory default path contains the PUBLIC
69  * namespace (if it exists), preceded by the user's personal namespace
70  * (if one exists).
71  *
72  * If namespaceSearchPathValid is false, then namespaceSearchPath (and the
73  * derived variables) need to be recomputed from namespace_search_path.
74  * We mark it invalid upon an assignment to namespace_search_path or receipt
75  * of a syscache invalidation event for pg_namespace.  The recomputation
76  * is done during the next lookup attempt.
77  *
78  * Any namespaces mentioned in namespace_search_path that are not readable
79  * by the current user ID are simply left out of namespaceSearchPath; so
80  * we have to be willing to recompute the path when current userid changes.
81  * namespaceUser is the userid the path has been computed for.
82  */
83
84 static List *namespaceSearchPath = NIL;
85
86 static bool namespaceSearchPathValid = true;
87
88 static Oid      namespaceUser = InvalidOid;
89
90 /* this flag must be updated correctly when namespaceSearchPath is changed */
91 static bool pathContainsSystemNamespace = false;
92
93 /* default place to create stuff; if InvalidOid, no default */
94 static Oid      defaultCreationNamespace = InvalidOid;
95
96 /*
97  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
98  * in a particular backend session (this happens when a CREATE TEMP TABLE
99  * command is first executed).  Thereafter it's the OID of the temp namespace.
100  */
101 static Oid      myTempNamespace = InvalidOid;
102
103 /*
104  * This is the text equivalent of the search path --- it's the value
105  * of the GUC variable 'search_path'.
106  */
107 char *namespace_search_path = NULL;
108
109
110 /*
111  * Deletion ordering constraint item.
112  */
113 typedef struct DelConstraint
114 {
115         Oid                     referencer;             /* table to delete first */
116         Oid                     referencee;             /* table to delete second */
117         int                     pred;                   /* workspace for TopoSortRels */
118         struct DelConstraint *link;     /* workspace for TopoSortRels */
119 } DelConstraint;
120
121
122 /* Local functions */
123 static void recomputeNamespacePath(void);
124 static Oid      GetTempTableNamespace(void);
125 static void RemoveTempRelations(Oid tempNamespaceId);
126 static List *FindTempRelations(Oid tempNamespaceId);
127 static List *FindDeletionConstraints(List *relOids);
128 static List *TopoSortRels(List *relOids, List *constraintList);
129 static void RemoveTempRelationsCallback(void);
130 static void NamespaceCallback(Datum arg, Oid relid);
131
132
133 /*
134  * RangeVarGetRelid
135  *              Given a RangeVar describing an existing relation,
136  *              select the proper namespace and look up the relation OID.
137  *
138  * If the relation is not found, return InvalidOid if failOK = true,
139  * otherwise raise an error.
140  */
141 Oid
142 RangeVarGetRelid(const RangeVar *relation, bool failOK)
143 {
144         Oid                     namespaceId;
145         Oid                     relId;
146
147         /*
148          * We check the catalog name and then ignore it.
149          */
150         if (relation->catalogname)
151         {
152                 if (strcmp(relation->catalogname, DatabaseName) != 0)
153                         elog(ERROR, "Cross-database references are not implemented");
154         }
155
156         if (relation->schemaname)
157         {
158                 /* use exact schema given */
159                 AclResult       aclresult;
160
161                 namespaceId = GetSysCacheOid(NAMESPACENAME,
162                                                                          CStringGetDatum(relation->schemaname),
163                                                                          0, 0, 0);
164                 if (!OidIsValid(namespaceId))
165                         elog(ERROR, "Namespace \"%s\" does not exist",
166                                  relation->schemaname);
167                 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
168                 if (aclresult != ACLCHECK_OK)
169                         aclcheck_error(aclresult, relation->schemaname);
170
171                 relId = get_relname_relid(relation->relname, namespaceId);
172         }
173         else
174         {
175                 /* search the namespace path */
176                 relId = RelnameGetRelid(relation->relname);
177         }
178
179         if (!OidIsValid(relId) && !failOK)
180         {
181                 if (relation->schemaname)
182                         elog(ERROR, "Relation \"%s\".\"%s\" does not exist",
183                                  relation->schemaname, relation->relname);
184                 else
185                         elog(ERROR, "Relation \"%s\" does not exist",
186                                  relation->relname);
187         }
188         return relId;
189 }
190
191 /*
192  * RangeVarGetCreationNamespace
193  *              Given a RangeVar describing a to-be-created relation,
194  *              choose which namespace to create it in.
195  *
196  * Note: calling this may result in a CommandCounterIncrement operation.
197  * That will happen on the first request for a temp table in any particular
198  * backend run; we will need to either create or clean out the temp schema.
199  */
200 Oid
201 RangeVarGetCreationNamespace(const RangeVar *newRelation)
202 {
203         Oid                     namespaceId;
204
205         /*
206          * We check the catalog name and then ignore it.
207          */
208         if (newRelation->catalogname)
209         {
210                 if (strcmp(newRelation->catalogname, DatabaseName) != 0)
211                         elog(ERROR, "Cross-database references are not implemented");
212         }
213
214         if (newRelation->istemp)
215         {
216                 /* TEMP tables are created in our backend-local temp namespace */
217                 if (newRelation->schemaname)
218                         elog(ERROR, "TEMP tables may not specify a namespace");
219                 /* Initialize temp namespace if first time through */
220                 if (!OidIsValid(myTempNamespace))
221                         myTempNamespace = GetTempTableNamespace();
222                 return myTempNamespace;
223         }
224
225         if (newRelation->schemaname)
226         {
227                 /* use exact schema given */
228                 namespaceId = GetSysCacheOid(NAMESPACENAME,
229                                                                          CStringGetDatum(newRelation->schemaname),
230                                                                          0, 0, 0);
231                 if (!OidIsValid(namespaceId))
232                         elog(ERROR, "Namespace \"%s\" does not exist",
233                                  newRelation->schemaname);
234         }
235         else
236         {
237                 /* use the default creation namespace */
238                 recomputeNamespacePath();
239                 namespaceId = defaultCreationNamespace;
240                 if (!OidIsValid(namespaceId))
241                         elog(ERROR, "No namespace has been selected to create in");
242         }
243
244         /* Note: callers will check for CREATE rights when appropriate */
245
246         return namespaceId;
247 }
248
249 /*
250  * RelnameGetRelid
251  *              Try to resolve an unqualified relation name.
252  *              Returns OID if relation found in search path, else InvalidOid.
253  */
254 Oid
255 RelnameGetRelid(const char *relname)
256 {
257         Oid                     relid;
258         List       *lptr;
259
260         recomputeNamespacePath();
261
262         /*
263          * If a TEMP-table namespace has been set up, it is implicitly first
264          * in the search path.  We do not need to check USAGE permission.
265          */
266         if (OidIsValid(myTempNamespace))
267         {
268                 relid = get_relname_relid(relname, myTempNamespace);
269                 if (OidIsValid(relid))
270                         return relid;
271         }
272
273         /*
274          * If system namespace is not in path, implicitly search it before path.
275          * We do not check USAGE permission.
276          */
277         if (!pathContainsSystemNamespace)
278         {
279                 relid = get_relname_relid(relname, PG_CATALOG_NAMESPACE);
280                 if (OidIsValid(relid))
281                         return relid;
282         }
283
284         /*
285          * Else search the path
286          */
287         foreach(lptr, namespaceSearchPath)
288         {
289                 Oid                     namespaceId = (Oid) lfirsti(lptr);
290
291                 relid = get_relname_relid(relname, namespaceId);
292                 if (OidIsValid(relid))
293                         return relid;
294         }
295
296         /* Not found in path */
297         return InvalidOid;
298 }
299
300 /*
301  * RelationIsVisible
302  *              Determine whether a relation (identified by OID) is visible in the
303  *              current search path.  Visible means "would be found by searching
304  *              for the unqualified relation name".
305  */
306 bool
307 RelationIsVisible(Oid relid)
308 {
309         HeapTuple       reltup;
310         Form_pg_class relform;
311         Oid                     relnamespace;
312         bool            visible;
313
314         recomputeNamespacePath();
315
316         reltup = SearchSysCache(RELOID,
317                                                         ObjectIdGetDatum(relid),
318                                                         0, 0, 0);
319         if (!HeapTupleIsValid(reltup))
320                 elog(ERROR, "Cache lookup failed for relation %u", relid);
321         relform = (Form_pg_class) GETSTRUCT(reltup);
322
323         /*
324          * Quick check: if it ain't in the path at all, it ain't visible.
325          */
326         relnamespace = relform->relnamespace;
327         if (relnamespace != myTempNamespace &&
328                 relnamespace != PG_CATALOG_NAMESPACE &&
329                 !intMember(relnamespace, namespaceSearchPath))
330                 visible = false;
331         else
332         {
333                 /*
334                  * If it is in the path, it might still not be visible; it could be
335                  * hidden by another relation of the same name earlier in the path.
336                  * So we must do a slow check to see if this rel would be found by
337                  * RelnameGetRelid.
338                  */
339                 char       *relname = NameStr(relform->relname);
340
341                 visible = (RelnameGetRelid(relname) == relid);
342         }
343
344         ReleaseSysCache(reltup);
345
346         return visible;
347 }
348
349
350 /*
351  * TypenameGetTypid
352  *              Try to resolve an unqualified datatype name.
353  *              Returns OID if type found in search path, else InvalidOid.
354  *
355  * This is essentially the same as RelnameGetRelid, but we never search
356  * the TEMP table namespace --- there is no reason to refer to the types
357  * of temp tables, AFAICS.
358  */
359 Oid
360 TypenameGetTypid(const char *typname)
361 {
362         Oid                     typid;
363         List       *lptr;
364
365         recomputeNamespacePath();
366
367         /*
368          * If system namespace is not in path, implicitly search it before path
369          */
370         if (!pathContainsSystemNamespace)
371         {
372                 typid = GetSysCacheOid(TYPENAMENSP,
373                                                            PointerGetDatum(typname),
374                                                            ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
375                                                            0, 0);
376                 if (OidIsValid(typid))
377                         return typid;
378         }
379
380         /*
381          * Else search the path
382          */
383         foreach(lptr, namespaceSearchPath)
384         {
385                 Oid                     namespaceId = (Oid) lfirsti(lptr);
386
387                 typid = GetSysCacheOid(TYPENAMENSP,
388                                                            PointerGetDatum(typname),
389                                                            ObjectIdGetDatum(namespaceId),
390                                                            0, 0);
391                 if (OidIsValid(typid))
392                         return typid;
393         }
394
395         /* Not found in path */
396         return InvalidOid;
397 }
398
399 /*
400  * TypeIsVisible
401  *              Determine whether a type (identified by OID) is visible in the
402  *              current search path.  Visible means "would be found by searching
403  *              for the unqualified type name".
404  */
405 bool
406 TypeIsVisible(Oid typid)
407 {
408         HeapTuple       typtup;
409         Form_pg_type typform;
410         Oid                     typnamespace;
411         bool            visible;
412
413         recomputeNamespacePath();
414
415         typtup = SearchSysCache(TYPEOID,
416                                                         ObjectIdGetDatum(typid),
417                                                         0, 0, 0);
418         if (!HeapTupleIsValid(typtup))
419                 elog(ERROR, "Cache lookup failed for type %u", typid);
420         typform = (Form_pg_type) GETSTRUCT(typtup);
421
422         /*
423          * Quick check: if it ain't in the path at all, it ain't visible.
424          */
425         typnamespace = typform->typnamespace;
426         if (typnamespace != PG_CATALOG_NAMESPACE &&
427                 !intMember(typnamespace, namespaceSearchPath))
428                 visible = false;
429         else
430         {
431                 /*
432                  * If it is in the path, it might still not be visible; it could be
433                  * hidden by another type of the same name earlier in the path.
434                  * So we must do a slow check to see if this type would be found by
435                  * TypenameGetTypid.
436                  */
437                 char       *typname = NameStr(typform->typname);
438
439                 visible = (TypenameGetTypid(typname) == typid);
440         }
441
442         ReleaseSysCache(typtup);
443
444         return visible;
445 }
446
447
448 /*
449  * FuncnameGetCandidates
450  *              Given a possibly-qualified function name and argument count,
451  *              retrieve a list of the possible matches.
452  *
453  * If nargs is -1, we return all functions matching the given name,
454  * regardless of argument count.
455  *
456  * We search a single namespace if the function name is qualified, else
457  * all namespaces in the search path.  The return list will never contain
458  * multiple entries with identical argument lists --- in the multiple-
459  * namespace case, we arrange for entries in earlier namespaces to mask
460  * identical entries in later namespaces.
461  */
462 FuncCandidateList
463 FuncnameGetCandidates(List *names, int nargs)
464 {
465         FuncCandidateList resultList = NULL;
466         char       *catalogname;
467         char       *schemaname = NULL;
468         char       *funcname = NULL;
469         Oid                     namespaceId;
470         CatCList   *catlist;
471         int                     i;
472
473         /* deconstruct the name list */
474         switch (length(names))
475         {
476                 case 1:
477                         funcname = strVal(lfirst(names));
478                         break;
479                 case 2:
480                         schemaname = strVal(lfirst(names));
481                         funcname = strVal(lsecond(names));
482                         break;
483                 case 3:
484                         catalogname = strVal(lfirst(names));
485                         schemaname = strVal(lsecond(names));
486                         funcname = strVal(lfirst(lnext(lnext(names))));
487                         /*
488                          * We check the catalog name and then ignore it.
489                          */
490                         if (strcmp(catalogname, DatabaseName) != 0)
491                                 elog(ERROR, "Cross-database references are not implemented");
492                         break;
493                 default:
494                         elog(ERROR, "Improper qualified name (too many dotted names)");
495                         break;
496         }
497
498         if (schemaname)
499         {
500                 /* use exact schema given */
501                 AclResult       aclresult;
502
503                 namespaceId = GetSysCacheOid(NAMESPACENAME,
504                                                                          CStringGetDatum(schemaname),
505                                                                          0, 0, 0);
506                 if (!OidIsValid(namespaceId))
507                         elog(ERROR, "Namespace \"%s\" does not exist",
508                                  schemaname);
509                 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
510                 if (aclresult != ACLCHECK_OK)
511                         aclcheck_error(aclresult, schemaname);
512         }
513         else
514         {
515                 /* flag to indicate we need namespace search */
516                 namespaceId = InvalidOid;
517                 recomputeNamespacePath();
518         }
519
520         /* Search syscache by name and (optionally) nargs only */
521         if (nargs >= 0)
522                 catlist = SearchSysCacheList(PROCNAMENSP, 2,
523                                                                          CStringGetDatum(funcname),
524                                                                          Int16GetDatum(nargs),
525                                                                          0, 0);
526         else
527                 catlist = SearchSysCacheList(PROCNAMENSP, 1,
528                                                                          CStringGetDatum(funcname),
529                                                                          0, 0, 0);
530
531         for (i = 0; i < catlist->n_members; i++)
532         {
533                 HeapTuple       proctup = &catlist->members[i]->tuple;
534                 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
535                 int                     pathpos = 0;
536                 FuncCandidateList newResult;
537
538                 nargs = procform->pronargs;
539
540                 if (OidIsValid(namespaceId))
541                 {
542                         /* Consider only procs in specified namespace */
543                         if (procform->pronamespace != namespaceId)
544                                 continue;
545                         /* No need to check args, they must all be different */
546                 }
547                 else
548                 {
549                         /* Consider only procs that are in the search path */
550                         if (pathContainsSystemNamespace ||
551                                 !IsSystemNamespace(procform->pronamespace))
552                         {
553                                 List       *nsp;
554
555                                 foreach(nsp, namespaceSearchPath)
556                                 {
557                                         pathpos++;
558                                         if (procform->pronamespace == (Oid) lfirsti(nsp))
559                                                 break;
560                                 }
561                                 if (nsp == NIL)
562                                         continue;       /* proc is not in search path */
563                         }
564
565                         /*
566                          * Okay, it's in the search path, but does it have the same
567                          * arguments as something we already accepted?  If so, keep
568                          * only the one that appears earlier in the search path.
569                          *
570                          * If we have an ordered list from SearchSysCacheList (the
571                          * normal case), then any conflicting proc must immediately
572                          * adjoin this one in the list, so we only need to look at
573                          * the newest result item.  If we have an unordered list,
574                          * we have to scan the whole result list.
575                          */
576                         if (resultList)
577                         {
578                                 FuncCandidateList       prevResult;
579
580                                 if (catlist->ordered)
581                                 {
582                                         if (nargs == resultList->nargs &&
583                                                 memcmp(procform->proargtypes, resultList->args,
584                                                            nargs * sizeof(Oid)) == 0)
585                                                 prevResult = resultList;
586                                         else
587                                                 prevResult = NULL;
588                                 }
589                                 else
590                                 {
591                                         for (prevResult = resultList;
592                                                  prevResult;
593                                                  prevResult = prevResult->next)
594                                         {
595                                                 if (nargs == prevResult->nargs &&
596                                                         memcmp(procform->proargtypes, prevResult->args,
597                                                                    nargs * sizeof(Oid)) == 0)
598                                                         break;
599                                         }
600                                 }
601                                 if (prevResult)
602                                 {
603                                         /* We have a match with a previous result */
604                                         Assert(pathpos != prevResult->pathpos);
605                                         if (pathpos > prevResult->pathpos)
606                                                 continue; /* keep previous result */
607                                         /* replace previous result */
608                                         prevResult->pathpos = pathpos;
609                                         prevResult->oid = proctup->t_data->t_oid;
610                                         continue;       /* args are same, of course */
611                                 }
612                         }
613                 }
614
615                 /*
616                  * Okay to add it to result list
617                  */
618                 newResult = (FuncCandidateList)
619                         palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
620                                    + nargs * sizeof(Oid));
621                 newResult->pathpos = pathpos;
622                 newResult->oid = proctup->t_data->t_oid;
623                 newResult->nargs = nargs;
624                 memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid));
625
626                 newResult->next = resultList;
627                 resultList = newResult;
628         }
629
630         ReleaseSysCacheList(catlist);
631
632         return resultList;
633 }
634
635 /*
636  * FunctionIsVisible
637  *              Determine whether a function (identified by OID) is visible in the
638  *              current search path.  Visible means "would be found by searching
639  *              for the unqualified function name with exact argument matches".
640  */
641 bool
642 FunctionIsVisible(Oid funcid)
643 {
644         HeapTuple       proctup;
645         Form_pg_proc procform;
646         Oid                     pronamespace;
647         bool            visible;
648
649         recomputeNamespacePath();
650
651         proctup = SearchSysCache(PROCOID,
652                                                          ObjectIdGetDatum(funcid),
653                                                          0, 0, 0);
654         if (!HeapTupleIsValid(proctup))
655                 elog(ERROR, "Cache lookup failed for procedure %u", funcid);
656         procform = (Form_pg_proc) GETSTRUCT(proctup);
657
658         /*
659          * Quick check: if it ain't in the path at all, it ain't visible.
660          */
661         pronamespace = procform->pronamespace;
662         if (pronamespace != PG_CATALOG_NAMESPACE &&
663                 !intMember(pronamespace, namespaceSearchPath))
664                 visible = false;
665         else
666         {
667                 /*
668                  * If it is in the path, it might still not be visible; it could be
669                  * hidden by another proc of the same name and arguments earlier
670                  * in the path.  So we must do a slow check to see if this is the
671                  * same proc that would be found by FuncnameGetCandidates.
672                  */
673                 char       *proname = NameStr(procform->proname);
674                 int                     nargs = procform->pronargs;
675                 FuncCandidateList clist;
676
677                 visible = false;
678
679                 clist = FuncnameGetCandidates(makeList1(makeString(proname)), nargs);
680
681                 for (; clist; clist = clist->next)
682                 {
683                         if (memcmp(clist->args, procform->proargtypes,
684                                            nargs * sizeof(Oid)) == 0)
685                         {
686                                 /* Found the expected entry; is it the right proc? */
687                                 visible = (clist->oid == funcid);
688                                 break;
689                         }
690                 }
691         }
692
693         ReleaseSysCache(proctup);
694
695         return visible;
696 }
697
698
699 /*
700  * OpernameGetCandidates
701  *              Given a possibly-qualified operator name and operator kind,
702  *              retrieve a list of the possible matches.
703  *
704  * If oprkind is '\0', we return all operators matching the given name,
705  * regardless of arguments.
706  *
707  * We search a single namespace if the operator name is qualified, else
708  * all namespaces in the search path.  The return list will never contain
709  * multiple entries with identical argument lists --- in the multiple-
710  * namespace case, we arrange for entries in earlier namespaces to mask
711  * identical entries in later namespaces.
712  *
713  * The returned items always have two args[] entries --- one or the other
714  * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
715  */
716 FuncCandidateList
717 OpernameGetCandidates(List *names, char oprkind)
718 {
719         FuncCandidateList resultList = NULL;
720         char       *catalogname;
721         char       *schemaname = NULL;
722         char       *opername = NULL;
723         Oid                     namespaceId;
724         CatCList   *catlist;
725         int                     i;
726
727         /* deconstruct the name list */
728         switch (length(names))
729         {
730                 case 1:
731                         opername = strVal(lfirst(names));
732                         break;
733                 case 2:
734                         schemaname = strVal(lfirst(names));
735                         opername = strVal(lsecond(names));
736                         break;
737                 case 3:
738                         catalogname = strVal(lfirst(names));
739                         schemaname = strVal(lsecond(names));
740                         opername = strVal(lfirst(lnext(lnext(names))));
741                         /*
742                          * We check the catalog name and then ignore it.
743                          */
744                         if (strcmp(catalogname, DatabaseName) != 0)
745                                 elog(ERROR, "Cross-database references are not implemented");
746                         break;
747                 default:
748                         elog(ERROR, "Improper qualified name (too many dotted names)");
749                         break;
750         }
751
752         if (schemaname)
753         {
754                 /* use exact schema given */
755                 AclResult       aclresult;
756
757                 namespaceId = GetSysCacheOid(NAMESPACENAME,
758                                                                          CStringGetDatum(schemaname),
759                                                                          0, 0, 0);
760                 if (!OidIsValid(namespaceId))
761                         elog(ERROR, "Namespace \"%s\" does not exist",
762                                  schemaname);
763                 aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
764                 if (aclresult != ACLCHECK_OK)
765                         aclcheck_error(aclresult, schemaname);
766         }
767         else
768         {
769                 /* flag to indicate we need namespace search */
770                 namespaceId = InvalidOid;
771                 recomputeNamespacePath();
772         }
773
774         /* Search syscache by name only */
775         catlist = SearchSysCacheList(OPERNAMENSP, 1,
776                                                                  CStringGetDatum(opername),
777                                                                  0, 0, 0);
778
779         for (i = 0; i < catlist->n_members; i++)
780         {
781                 HeapTuple       opertup = &catlist->members[i]->tuple;
782                 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
783                 int                     pathpos = 0;
784                 FuncCandidateList newResult;
785
786                 /* Ignore operators of wrong kind, if specific kind requested */
787                 if (oprkind && operform->oprkind != oprkind)
788                         continue;
789
790                 if (OidIsValid(namespaceId))
791                 {
792                         /* Consider only opers in specified namespace */
793                         if (operform->oprnamespace != namespaceId)
794                                 continue;
795                         /* No need to check args, they must all be different */
796                 }
797                 else
798                 {
799                         /* Consider only opers that are in the search path */
800                         if (pathContainsSystemNamespace ||
801                                 !IsSystemNamespace(operform->oprnamespace))
802                         {
803                                 List       *nsp;
804
805                                 foreach(nsp, namespaceSearchPath)
806                                 {
807                                         pathpos++;
808                                         if (operform->oprnamespace == (Oid) lfirsti(nsp))
809                                                 break;
810                                 }
811                                 if (nsp == NIL)
812                                         continue;       /* oper is not in search path */
813                         }
814
815                         /*
816                          * Okay, it's in the search path, but does it have the same
817                          * arguments as something we already accepted?  If so, keep
818                          * only the one that appears earlier in the search path.
819                          *
820                          * If we have an ordered list from SearchSysCacheList (the
821                          * normal case), then any conflicting oper must immediately
822                          * adjoin this one in the list, so we only need to look at
823                          * the newest result item.  If we have an unordered list,
824                          * we have to scan the whole result list.
825                          */
826                         if (resultList)
827                         {
828                                 FuncCandidateList       prevResult;
829
830                                 if (catlist->ordered)
831                                 {
832                                         if (operform->oprleft == resultList->args[0] &&
833                                                 operform->oprright == resultList->args[1])
834                                                 prevResult = resultList;
835                                         else
836                                                 prevResult = NULL;
837                                 }
838                                 else
839                                 {
840                                         for (prevResult = resultList;
841                                                  prevResult;
842                                                  prevResult = prevResult->next)
843                                         {
844                                                 if (operform->oprleft == prevResult->args[0] &&
845                                                         operform->oprright == prevResult->args[1])
846                                                         break;
847                                         }
848                                 }
849                                 if (prevResult)
850                                 {
851                                         /* We have a match with a previous result */
852                                         Assert(pathpos != prevResult->pathpos);
853                                         if (pathpos > prevResult->pathpos)
854                                                 continue; /* keep previous result */
855                                         /* replace previous result */
856                                         prevResult->pathpos = pathpos;
857                                         prevResult->oid = opertup->t_data->t_oid;
858                                         continue;       /* args are same, of course */
859                                 }
860                         }
861                 }
862
863                 /*
864                  * Okay to add it to result list
865                  */
866                 newResult = (FuncCandidateList)
867                         palloc(sizeof(struct _FuncCandidateList) + sizeof(Oid));
868                 newResult->pathpos = pathpos;
869                 newResult->oid = opertup->t_data->t_oid;
870                 newResult->nargs = 2;
871                 newResult->args[0] = operform->oprleft;
872                 newResult->args[1] = operform->oprright;
873                 newResult->next = resultList;
874                 resultList = newResult;
875         }
876
877         ReleaseSysCacheList(catlist);
878
879         return resultList;
880 }
881
882 /*
883  * OperatorIsVisible
884  *              Determine whether an operator (identified by OID) is visible in the
885  *              current search path.  Visible means "would be found by searching
886  *              for the unqualified operator name with exact argument matches".
887  */
888 bool
889 OperatorIsVisible(Oid oprid)
890 {
891         HeapTuple       oprtup;
892         Form_pg_operator oprform;
893         Oid                     oprnamespace;
894         bool            visible;
895
896         recomputeNamespacePath();
897
898         oprtup = SearchSysCache(OPEROID,
899                                                         ObjectIdGetDatum(oprid),
900                                                         0, 0, 0);
901         if (!HeapTupleIsValid(oprtup))
902                 elog(ERROR, "Cache lookup failed for operator %u", oprid);
903         oprform = (Form_pg_operator) GETSTRUCT(oprtup);
904
905         /*
906          * Quick check: if it ain't in the path at all, it ain't visible.
907          */
908         oprnamespace = oprform->oprnamespace;
909         if (oprnamespace != PG_CATALOG_NAMESPACE &&
910                 !intMember(oprnamespace, namespaceSearchPath))
911                 visible = false;
912         else
913         {
914                 /*
915                  * If it is in the path, it might still not be visible; it could be
916                  * hidden by another operator of the same name and arguments earlier
917                  * in the path.  So we must do a slow check to see if this is the
918                  * same operator that would be found by OpernameGetCandidates.
919                  */
920                 char       *oprname = NameStr(oprform->oprname);
921                 FuncCandidateList clist;
922
923                 visible = false;
924
925                 clist = OpernameGetCandidates(makeList1(makeString(oprname)),
926                                                                           oprform->oprkind);
927
928                 for (; clist; clist = clist->next)
929                 {
930                         if (clist->args[0] == oprform->oprleft &&
931                                 clist->args[1] == oprform->oprright)
932                         {
933                                 /* Found the expected entry; is it the right op? */
934                                 visible = (clist->oid == oprid);
935                                 break;
936                         }
937                 }
938         }
939
940         ReleaseSysCache(oprtup);
941
942         return visible;
943 }
944
945
946 /*
947  * OpclassGetCandidates
948  *              Given an index access method OID, retrieve a list of all the
949  *              opclasses for that AM that are visible in the search path.
950  *
951  * NOTE: the opcname_tmp field in the returned structs should not be used
952  * by callers, because it points at syscache entries that we release at
953  * the end of this routine.  If any callers needed the name information,
954  * we could pstrdup() the names ... but at present it'd be wasteful.
955  */
956 OpclassCandidateList
957 OpclassGetCandidates(Oid amid)
958 {
959         OpclassCandidateList resultList = NULL;
960         CatCList   *catlist;
961         int                     i;
962
963         recomputeNamespacePath();
964
965         /* Search syscache by AM OID only */
966         catlist = SearchSysCacheList(CLAAMNAMENSP, 1,
967                                                                  ObjectIdGetDatum(amid),
968                                                                  0, 0, 0);
969
970         for (i = 0; i < catlist->n_members; i++)
971         {
972                 HeapTuple       opctup = &catlist->members[i]->tuple;
973                 Form_pg_opclass opcform = (Form_pg_opclass) GETSTRUCT(opctup);
974                 int                     pathpos = 0;
975                 OpclassCandidateList newResult;
976
977                 /* Consider only opclasses that are in the search path */
978                 if (pathContainsSystemNamespace ||
979                         !IsSystemNamespace(opcform->opcnamespace))
980                 {
981                         List       *nsp;
982
983                         foreach(nsp, namespaceSearchPath)
984                         {
985                                 pathpos++;
986                                 if (opcform->opcnamespace == (Oid) lfirsti(nsp))
987                                         break;
988                         }
989                         if (nsp == NIL)
990                                 continue;               /* opclass is not in search path */
991                 }
992
993                 /*
994                  * Okay, it's in the search path, but does it have the same name
995                  * as something we already accepted?  If so, keep
996                  * only the one that appears earlier in the search path.
997                  *
998                  * If we have an ordered list from SearchSysCacheList (the
999                  * normal case), then any conflicting opclass must immediately
1000                  * adjoin this one in the list, so we only need to look at
1001                  * the newest result item.  If we have an unordered list,
1002                  * we have to scan the whole result list.
1003                  */
1004                 if (resultList)
1005                 {
1006                         OpclassCandidateList    prevResult;
1007
1008                         if (catlist->ordered)
1009                         {
1010                                 if (strcmp(NameStr(opcform->opcname),
1011                                                    resultList->opcname_tmp) == 0)
1012                                         prevResult = resultList;
1013                                 else
1014                                         prevResult = NULL;
1015                         }
1016                         else
1017                         {
1018                                 for (prevResult = resultList;
1019                                          prevResult;
1020                                          prevResult = prevResult->next)
1021                                 {
1022                                         if (strcmp(NameStr(opcform->opcname),
1023                                                            prevResult->opcname_tmp) == 0)
1024                                                 break;
1025                                 }
1026                         }
1027                         if (prevResult)
1028                         {
1029                                 /* We have a match with a previous result */
1030                                 Assert(pathpos != prevResult->pathpos);
1031                                 if (pathpos > prevResult->pathpos)
1032                                         continue; /* keep previous result */
1033                                 /* replace previous result */
1034                                 prevResult->opcname_tmp = NameStr(opcform->opcname);
1035                                 prevResult->pathpos = pathpos;
1036                                 prevResult->oid = opctup->t_data->t_oid;
1037                                 prevResult->opcintype = opcform->opcintype;
1038                                 prevResult->opcdefault = opcform->opcdefault;
1039                                 prevResult->opckeytype = opcform->opckeytype;
1040                                 continue;
1041                         }
1042                 }
1043
1044                 /*
1045                  * Okay to add it to result list
1046                  */
1047                 newResult = (OpclassCandidateList)
1048                         palloc(sizeof(struct _OpclassCandidateList));
1049                 newResult->opcname_tmp = NameStr(opcform->opcname);
1050                 newResult->pathpos = pathpos;
1051                 newResult->oid = opctup->t_data->t_oid;
1052                 newResult->opcintype = opcform->opcintype;
1053                 newResult->opcdefault = opcform->opcdefault;
1054                 newResult->opckeytype = opcform->opckeytype;
1055                 newResult->next = resultList;
1056                 resultList = newResult;
1057         }
1058
1059         ReleaseSysCacheList(catlist);
1060
1061         return resultList;
1062 }
1063
1064 /*
1065  * OpclassnameGetOpcid
1066  *              Try to resolve an unqualified index opclass name.
1067  *              Returns OID if opclass found in search path, else InvalidOid.
1068  *
1069  * This is essentially the same as TypenameGetTypid, but we have to have
1070  * an extra argument for the index AM OID.
1071  */
1072 Oid
1073 OpclassnameGetOpcid(Oid amid, const char *opcname)
1074 {
1075         Oid                     opcid;
1076         List       *lptr;
1077
1078         recomputeNamespacePath();
1079
1080         /*
1081          * If system namespace is not in path, implicitly search it before path
1082          */
1083         if (!pathContainsSystemNamespace)
1084         {
1085                 opcid = GetSysCacheOid(CLAAMNAMENSP,
1086                                                            ObjectIdGetDatum(amid),
1087                                                            PointerGetDatum(opcname),
1088                                                            ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
1089                                                            0);
1090                 if (OidIsValid(opcid))
1091                         return opcid;
1092         }
1093
1094         /*
1095          * Else search the path
1096          */
1097         foreach(lptr, namespaceSearchPath)
1098         {
1099                 Oid                     namespaceId = (Oid) lfirsti(lptr);
1100
1101                 opcid = GetSysCacheOid(CLAAMNAMENSP,
1102                                                            ObjectIdGetDatum(amid),
1103                                                            PointerGetDatum(opcname),
1104                                                            ObjectIdGetDatum(namespaceId),
1105                                                            0);
1106                 if (OidIsValid(opcid))
1107                         return opcid;
1108         }
1109
1110         /* Not found in path */
1111         return InvalidOid;
1112 }
1113
1114 /*
1115  * OpclassIsVisible
1116  *              Determine whether an opclass (identified by OID) is visible in the
1117  *              current search path.  Visible means "would be found by searching
1118  *              for the unqualified opclass name".
1119  */
1120 bool
1121 OpclassIsVisible(Oid opcid)
1122 {
1123         HeapTuple       opctup;
1124         Form_pg_opclass opcform;
1125         Oid                     opcnamespace;
1126         bool            visible;
1127
1128         recomputeNamespacePath();
1129
1130         opctup = SearchSysCache(CLAOID,
1131                                                         ObjectIdGetDatum(opcid),
1132                                                         0, 0, 0);
1133         if (!HeapTupleIsValid(opctup))
1134                 elog(ERROR, "Cache lookup failed for opclass %u", opcid);
1135         opcform = (Form_pg_opclass) GETSTRUCT(opctup);
1136
1137         /*
1138          * Quick check: if it ain't in the path at all, it ain't visible.
1139          */
1140         opcnamespace = opcform->opcnamespace;
1141         if (opcnamespace != PG_CATALOG_NAMESPACE &&
1142                 !intMember(opcnamespace, namespaceSearchPath))
1143                 visible = false;
1144         else
1145         {
1146                 /*
1147                  * If it is in the path, it might still not be visible; it could be
1148                  * hidden by another opclass of the same name earlier in the path.
1149                  * So we must do a slow check to see if this opclass would be found by
1150                  * OpclassnameGetOpcid.
1151                  */
1152                 char       *opcname = NameStr(opcform->opcname);
1153
1154                 visible = (OpclassnameGetOpcid(opcform->opcamid, opcname) == opcid);
1155         }
1156
1157         ReleaseSysCache(opctup);
1158
1159         return visible;
1160 }
1161
1162
1163 /*
1164  * QualifiedNameGetCreationNamespace
1165  *              Given a possibly-qualified name for an object (in List-of-Values
1166  *              format), determine what namespace the object should be created in.
1167  *              Also extract and return the object name (last component of list).
1168  *
1169  * This is *not* used for tables.  Hence, the TEMP table namespace is
1170  * never selected as the creation target.
1171  */
1172 Oid
1173 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
1174 {
1175         char       *catalogname;
1176         char       *schemaname = NULL;
1177         char       *objname = NULL;
1178         Oid                     namespaceId;
1179
1180         /* deconstruct the name list */
1181         switch (length(names))
1182         {
1183                 case 1:
1184                         objname = strVal(lfirst(names));
1185                         break;
1186                 case 2:
1187                         schemaname = strVal(lfirst(names));
1188                         objname = strVal(lsecond(names));
1189                         break;
1190                 case 3:
1191                         catalogname = strVal(lfirst(names));
1192                         schemaname = strVal(lsecond(names));
1193                         objname = strVal(lfirst(lnext(lnext(names))));
1194                         /*
1195                          * We check the catalog name and then ignore it.
1196                          */
1197                         if (strcmp(catalogname, DatabaseName) != 0)
1198                                 elog(ERROR, "Cross-database references are not implemented");
1199                         break;
1200                 default:
1201                         elog(ERROR, "Improper qualified name (too many dotted names)");
1202                         break;
1203         }
1204
1205         if (schemaname)
1206         {
1207                 /* use exact schema given */
1208                 namespaceId = GetSysCacheOid(NAMESPACENAME,
1209                                                                          CStringGetDatum(schemaname),
1210                                                                          0, 0, 0);
1211                 if (!OidIsValid(namespaceId))
1212                         elog(ERROR, "Namespace \"%s\" does not exist",
1213                                  schemaname);
1214         }
1215         else
1216         {
1217                 /* use the default creation namespace */
1218                 recomputeNamespacePath();
1219                 namespaceId = defaultCreationNamespace;
1220                 if (!OidIsValid(namespaceId))
1221                         elog(ERROR, "No namespace has been selected to create in");
1222         }
1223
1224         /* Note: callers will check for CREATE rights when appropriate */
1225
1226         *objname_p = objname;
1227         return namespaceId;
1228 }
1229
1230 /*
1231  * makeRangeVarFromNameList
1232  *              Utility routine to convert a qualified-name list into RangeVar form.
1233  */
1234 RangeVar *
1235 makeRangeVarFromNameList(List *names)
1236 {
1237         RangeVar   *rel = makeRangeVar(NULL, NULL);
1238
1239         switch (length(names))
1240         {
1241                 case 1:
1242                         rel->relname = strVal(lfirst(names));
1243                         break;
1244                 case 2:
1245                         rel->schemaname = strVal(lfirst(names));
1246                         rel->relname = strVal(lsecond(names));
1247                         break;
1248                 case 3:
1249                         rel->catalogname = strVal(lfirst(names));
1250                         rel->schemaname = strVal(lsecond(names));
1251                         rel->relname = strVal(lfirst(lnext(lnext(names))));
1252                         break;
1253                 default:
1254                         elog(ERROR, "Improper relation name (too many dotted names)");
1255                         break;
1256         }
1257
1258         return rel;
1259 }
1260
1261 /*
1262  * NameListToString
1263  *              Utility routine to convert a qualified-name list into a string.
1264  *              Used primarily to form error messages.
1265  */
1266 char *
1267 NameListToString(List *names)
1268 {
1269         StringInfoData string;
1270         List            *l;
1271
1272         initStringInfo(&string);
1273
1274         foreach(l, names)
1275         {
1276                 if (l != names)
1277                         appendStringInfoChar(&string, '.');
1278                 appendStringInfo(&string, "%s", strVal(lfirst(l)));
1279         }
1280
1281         return string.data;
1282 }
1283
1284 /*
1285  * isTempNamespace - is the given namespace my temporary-table namespace?
1286  */
1287 bool
1288 isTempNamespace(Oid namespaceId)
1289 {
1290         if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
1291                 return true;
1292         return false;
1293 }
1294
1295
1296 /*
1297  * recomputeNamespacePath - recompute path derived variables if needed.
1298  */
1299 static void
1300 recomputeNamespacePath(void)
1301 {
1302         Oid                     userId = GetUserId();
1303         char       *rawname;
1304         List       *namelist;
1305         List       *oidlist;
1306         List       *newpath;
1307         List       *l;
1308         MemoryContext oldcxt;
1309
1310         /*
1311          * Do nothing if path is already valid.
1312          */
1313         if (namespaceSearchPathValid && namespaceUser == userId)
1314                 return;
1315
1316         /* Need a modifiable copy of namespace_search_path string */
1317         rawname = pstrdup(namespace_search_path);
1318
1319         /* Parse string into list of identifiers */
1320         if (!SplitIdentifierString(rawname, ',', &namelist))
1321         {
1322                 /* syntax error in name list */
1323                 /* this should not happen if GUC checked check_search_path */
1324                 elog(ERROR, "recomputeNamespacePath: invalid list syntax");
1325         }
1326
1327         /*
1328          * Convert the list of names to a list of OIDs.  If any names are not
1329          * recognizable or we don't have read access, just leave them out of
1330          * the list.  (We can't raise an error, since the search_path setting
1331          * has already been accepted.)
1332          */
1333         oidlist = NIL;
1334         foreach(l, namelist)
1335         {
1336                 char   *curname = (char *) lfirst(l);
1337                 Oid             namespaceId;
1338
1339                 if (strcmp(curname, "$user") == 0)
1340                 {
1341                         /* $user --- substitute namespace matching user name, if any */
1342                         HeapTuple       tuple;
1343
1344                         tuple = SearchSysCache(SHADOWSYSID,
1345                                                                    ObjectIdGetDatum(userId),
1346                                                                    0, 0, 0);
1347                         if (HeapTupleIsValid(tuple))
1348                         {
1349                                 char   *uname;
1350
1351                                 uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
1352                                 namespaceId = GetSysCacheOid(NAMESPACENAME,
1353                                                                                          CStringGetDatum(uname),
1354                                                                                          0, 0, 0);
1355                                 ReleaseSysCache(tuple);
1356                                 if (OidIsValid(namespaceId) &&
1357                                         pg_namespace_aclcheck(namespaceId, userId,
1358                                                                                   ACL_USAGE) == ACLCHECK_OK)
1359                                         oidlist = lappendi(oidlist, namespaceId);
1360                         }
1361                 }
1362                 else
1363                 {
1364                         /* normal namespace reference */
1365                         namespaceId = GetSysCacheOid(NAMESPACENAME,
1366                                                                                  CStringGetDatum(curname),
1367                                                                                  0, 0, 0);
1368                         if (OidIsValid(namespaceId) &&
1369                                 pg_namespace_aclcheck(namespaceId, userId,
1370                                                                           ACL_USAGE) == ACLCHECK_OK)
1371                                 oidlist = lappendi(oidlist, namespaceId);
1372                 }
1373         }
1374
1375         /*
1376          * Now that we've successfully built the new list of namespace OIDs,
1377          * save it in permanent storage.
1378          */
1379         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1380         newpath = listCopy(oidlist);
1381         MemoryContextSwitchTo(oldcxt);
1382
1383         /* Now safe to assign to state variable. */
1384         freeList(namespaceSearchPath);
1385         namespaceSearchPath = newpath;
1386
1387         /*
1388          * Update info derived from search path.
1389          */
1390         pathContainsSystemNamespace = intMember(PG_CATALOG_NAMESPACE,
1391                                                                                         namespaceSearchPath);
1392
1393         if (namespaceSearchPath == NIL)
1394                 defaultCreationNamespace = InvalidOid;
1395         else
1396                 defaultCreationNamespace = (Oid) lfirsti(namespaceSearchPath);
1397
1398         /* Mark the path valid. */
1399         namespaceSearchPathValid = true;
1400         namespaceUser = userId;
1401
1402         /* Clean up. */
1403         pfree(rawname);
1404         freeList(namelist);
1405         freeList(oidlist);
1406 }
1407
1408 /*
1409  * GetTempTableNamespace
1410  *              Initialize temp table namespace on first use in a particular backend
1411  */
1412 static Oid
1413 GetTempTableNamespace(void)
1414 {
1415         char            namespaceName[NAMEDATALEN];
1416         Oid                     namespaceId;
1417
1418         /*
1419          * First, do permission check to see if we are authorized to make
1420          * temp tables.  We use a nonstandard error message here since
1421          * "databasename: permission denied" might be a tad cryptic.
1422          *
1423          * Note we apply the check to the session user, not the currently
1424          * active userid, since we are not going to change our minds about
1425          * temp table availability during the session.
1426          */
1427         if (pg_database_aclcheck(MyDatabaseId, GetSessionUserId(),
1428                                                          ACL_CREATE_TEMP) != ACLCHECK_OK)
1429                 elog(ERROR, "%s: not authorized to create temp tables",
1430                          DatabaseName);
1431
1432         snprintf(namespaceName, NAMEDATALEN, "pg_temp_%d", MyBackendId);
1433
1434         namespaceId = GetSysCacheOid(NAMESPACENAME,
1435                                                                  CStringGetDatum(namespaceName),
1436                                                                  0, 0, 0);
1437         if (!OidIsValid(namespaceId))
1438         {
1439                 /*
1440                  * First use of this temp namespace in this database; create it.
1441                  * The temp namespaces are always owned by the superuser.  We
1442                  * leave their permissions at default --- i.e., no access except to
1443                  * superuser --- to ensure that unprivileged users can't peek
1444                  * at other backends' temp tables.  This works because the places
1445                  * that access the temp namespace for my own backend skip permissions
1446                  * checks on it.
1447                  */
1448                 namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID);
1449                 /* Advance command counter to make namespace visible */
1450                 CommandCounterIncrement();
1451         }
1452         else
1453         {
1454                 /*
1455                  * If the namespace already exists, clean it out (in case the
1456                  * former owner crashed without doing so).
1457                  */
1458                 RemoveTempRelations(namespaceId);
1459         }
1460
1461         /*
1462          * Register exit callback to clean out temp tables at backend shutdown.
1463          */
1464         on_shmem_exit(RemoveTempRelationsCallback, 0);
1465
1466         return namespaceId;
1467 }
1468
1469 /*
1470  * Remove all relations in the specified temp namespace.
1471  *
1472  * This is called at backend shutdown (if we made any temp relations).
1473  * It is also called when we begin using a pre-existing temp namespace,
1474  * in order to clean out any relations that might have been created by
1475  * a crashed backend.
1476  */
1477 static void
1478 RemoveTempRelations(Oid tempNamespaceId)
1479 {
1480         List       *tempRelList;
1481         List       *constraintList;
1482         List       *lptr;
1483
1484         /* Get a list of relations to delete */
1485         tempRelList = FindTempRelations(tempNamespaceId);
1486
1487         if (tempRelList == NIL)
1488                 return;                                 /* nothing to do */
1489
1490         /* If more than one, sort them to respect any deletion-order constraints */
1491         if (length(tempRelList) > 1)
1492         {
1493                 constraintList = FindDeletionConstraints(tempRelList);
1494                 if (constraintList != NIL)
1495                         tempRelList = TopoSortRels(tempRelList, constraintList);
1496         }
1497
1498         /* Scan the list and delete all entries */
1499         foreach(lptr, tempRelList)
1500         {
1501                 Oid                     reloid = (Oid) lfirsti(lptr);
1502
1503                 heap_drop_with_catalog(reloid, true);
1504                 /*
1505                  * Advance cmd counter to make catalog changes visible, in case
1506                  * a later entry depends on this one.
1507                  */
1508                 CommandCounterIncrement();
1509         }
1510 }
1511
1512 /*
1513  * Find all relations in the specified temp namespace.
1514  *
1515  * Returns a list of relation OIDs.
1516  */
1517 static List *
1518 FindTempRelations(Oid tempNamespaceId)
1519 {
1520         List       *tempRelList = NIL;
1521         Relation        pgclass;
1522         HeapScanDesc scan;
1523         HeapTuple       tuple;
1524         ScanKeyData key;
1525
1526         /*
1527          * Scan pg_class to find all the relations in the target namespace.
1528          * Ignore indexes, though, on the assumption that they'll go away
1529          * when their tables are deleted.
1530          */
1531         ScanKeyEntryInitialize(&key, 0x0,
1532                                                    Anum_pg_class_relnamespace,
1533                                                    F_OIDEQ,
1534                                                    ObjectIdGetDatum(tempNamespaceId));
1535
1536         pgclass = heap_openr(RelationRelationName, AccessShareLock);
1537         scan = heap_beginscan(pgclass, false, SnapshotNow, 1, &key);
1538
1539         while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
1540         {
1541                 switch (((Form_pg_class) GETSTRUCT(tuple))->relkind)
1542                 {
1543                         case RELKIND_RELATION:
1544                         case RELKIND_SEQUENCE:
1545                         case RELKIND_VIEW:
1546                                 tempRelList = lconsi(tuple->t_data->t_oid, tempRelList);
1547                                 break;
1548                         default:
1549                                 break;
1550                 }
1551         }
1552
1553         heap_endscan(scan);
1554         heap_close(pgclass, AccessShareLock);
1555
1556         return tempRelList;
1557 }
1558
1559 /*
1560  * Find deletion-order constraints involving the given relation OIDs.
1561  *
1562  * Returns a list of DelConstraint objects.
1563  */
1564 static List *
1565 FindDeletionConstraints(List *relOids)
1566 {
1567         List       *constraintList = NIL;
1568         Relation        inheritsrel;
1569         HeapScanDesc scan;
1570         HeapTuple       tuple;
1571
1572         /*
1573          * Scan pg_inherits to find parents and children that are in the list.
1574          */
1575         inheritsrel = heap_openr(InheritsRelationName, AccessShareLock);
1576         scan = heap_beginscan(inheritsrel, 0, SnapshotNow, 0, NULL);
1577
1578         while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
1579         {
1580                 Oid             inhrelid = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid;
1581                 Oid             inhparent = ((Form_pg_inherits) GETSTRUCT(tuple))->inhparent;
1582
1583                 if (intMember(inhrelid, relOids) && intMember(inhparent, relOids))
1584                 {
1585                         DelConstraint  *item;
1586
1587                         item = (DelConstraint *) palloc(sizeof(DelConstraint));
1588                         item->referencer = inhrelid;
1589                         item->referencee = inhparent;
1590                         constraintList = lcons(item, constraintList);
1591                 }
1592         }
1593
1594         heap_endscan(scan);
1595         heap_close(inheritsrel, AccessShareLock);
1596
1597         return constraintList;
1598 }
1599
1600 /*
1601  * TopoSortRels -- topological sort of a list of rels to delete
1602  *
1603  * This is a lot simpler and slower than, for example, the topological sort
1604  * algorithm shown in Knuth's Volume 1.  However, we are not likely to be
1605  * working with more than a few constraints, so the apparent slowness of the
1606  * algorithm won't really matter.
1607  */
1608 static List *
1609 TopoSortRels(List *relOids, List *constraintList)
1610 {
1611         int                     queue_size = length(relOids);
1612         Oid                *rels;
1613         int                *beforeConstraints;
1614         DelConstraint **afterConstraints;
1615         List       *resultList = NIL;
1616         List       *lptr;
1617         int                     i,
1618                                 j,
1619                                 k,
1620                                 last;
1621
1622         /* Allocate workspace */
1623         rels = (Oid *) palloc(queue_size * sizeof(Oid));
1624         beforeConstraints = (int *) palloc(queue_size * sizeof(int));
1625         afterConstraints = (DelConstraint **)
1626                 palloc(queue_size * sizeof(DelConstraint*));
1627
1628         /* Build an array of the target relation OIDs */
1629         i = 0;
1630         foreach(lptr, relOids)
1631         {
1632                 rels[i++] = (Oid) lfirsti(lptr);
1633         }
1634
1635         /*
1636          * Scan the constraints, and for each rel in the array, generate a
1637          * count of the number of constraints that say it must be before
1638          * something else, plus a list of the constraints that say it must be
1639          * after something else. The count for the j'th rel is stored in
1640          * beforeConstraints[j], and the head of its list in
1641          * afterConstraints[j].  Each constraint stores its list link in
1642          * its link field (note any constraint will be in just one list).
1643          * The array index for the before-rel of each constraint is
1644          * remembered in the constraint's pred field.
1645          */
1646         MemSet(beforeConstraints, 0, queue_size * sizeof(int));
1647         MemSet(afterConstraints, 0, queue_size * sizeof(DelConstraint*));
1648         foreach(lptr, constraintList)
1649         {
1650                 DelConstraint  *constraint = (DelConstraint *) lfirst(lptr);
1651                 Oid                     rel;
1652
1653                 /* Find the referencer rel in the array */
1654                 rel = constraint->referencer;
1655                 for (j = queue_size; --j >= 0;)
1656                 {
1657                         if (rels[j] == rel)
1658                                 break;
1659                 }
1660                 Assert(j >= 0);                 /* should have found a match */
1661                 /* Find the referencee rel in the array */
1662                 rel = constraint->referencee;
1663                 for (k = queue_size; --k >= 0;)
1664                 {
1665                         if (rels[k] == rel)
1666                                 break;
1667                 }
1668                 Assert(k >= 0);                 /* should have found a match */
1669                 beforeConstraints[j]++; /* referencer must come before */
1670                 /* add this constraint to list of after-constraints for referencee */
1671                 constraint->pred = j;
1672                 constraint->link = afterConstraints[k];
1673                 afterConstraints[k] = constraint;
1674         }
1675         /*--------------------
1676          * Now scan the rels array backwards.   At each step, output the
1677          * last rel that has no remaining before-constraints, and decrease
1678          * the beforeConstraints count of each of the rels it was constrained
1679          * against.  (This is the right order since we are building the result
1680          * list back-to-front.)
1681          * i = counter for number of rels left to output
1682          * j = search index for rels[]
1683          * dc = temp for scanning constraint list for rel j
1684          * last = last valid index in rels (avoid redundant searches)
1685          *--------------------
1686          */
1687         last = queue_size - 1;
1688         for (i = queue_size; --i >= 0;)
1689         {
1690                 DelConstraint  *dc;
1691
1692                 /* Find next candidate to output */
1693                 while (rels[last] == InvalidOid)
1694                         last--;
1695                 for (j = last; j >= 0; j--)
1696                 {
1697                         if (rels[j] != InvalidOid && beforeConstraints[j] == 0)
1698                                 break;
1699                 }
1700                 /* If no available candidate, topological sort fails */
1701                 if (j < 0)
1702                         elog(ERROR, "TopoSortRels: failed to find a workable deletion ordering");
1703                 /* Output candidate, and mark it done by zeroing rels[] entry */
1704                 resultList = lconsi(rels[j], resultList);
1705                 rels[j] = InvalidOid;
1706                 /* Update beforeConstraints counts of its predecessors */
1707                 for (dc = afterConstraints[j]; dc; dc = dc->link)
1708                         beforeConstraints[dc->pred]--;
1709         }
1710
1711         /* Done */
1712         return resultList;
1713 }
1714
1715 /*
1716  * Callback to remove temp relations at backend exit.
1717  */
1718 static void
1719 RemoveTempRelationsCallback(void)
1720 {
1721         if (OidIsValid(myTempNamespace)) /* should always be true */
1722         {
1723                 /* Need to ensure we have a usable transaction. */
1724                 AbortOutOfAnyTransaction();
1725                 StartTransactionCommand();
1726
1727                 RemoveTempRelations(myTempNamespace);
1728
1729                 CommitTransactionCommand();
1730         }
1731 }
1732
1733
1734 /*
1735  * Routines for handling the GUC variable 'search_path'.
1736  */
1737
1738 /* parse_hook: is proposed value valid? */
1739 bool
1740 check_search_path(const char *proposed)
1741 {
1742         char       *rawname;
1743         List       *namelist;
1744         List       *l;
1745
1746         /* Need a modifiable copy of string */
1747         rawname = pstrdup(proposed);
1748
1749         /* Parse string into list of identifiers */
1750         if (!SplitIdentifierString(rawname, ',', &namelist))
1751         {
1752                 /* syntax error in name list */
1753                 pfree(rawname);
1754                 freeList(namelist);
1755                 return false;
1756         }
1757
1758         /*
1759          * If we aren't inside a transaction, we cannot do database access so
1760          * cannot verify the individual names.  Must accept the list on faith.
1761          * (This case can happen, for example, when the postmaster reads a
1762          * search_path setting from postgresql.conf.)
1763          */
1764         if (!IsTransactionState())
1765         {
1766                 pfree(rawname);
1767                 freeList(namelist);
1768                 return true;
1769         }
1770
1771         /*
1772          * Verify that all the names are either valid namespace names or "$user".
1773          * We do not require $user to correspond to a valid namespace.
1774          * We do not check for USAGE rights, either; should we?
1775          */
1776         foreach(l, namelist)
1777         {
1778                 char   *curname = (char *) lfirst(l);
1779
1780                 if (strcmp(curname, "$user") == 0)
1781                         continue;
1782                 if (!SearchSysCacheExists(NAMESPACENAME,
1783                                                                   CStringGetDatum(curname),
1784                                                                   0, 0, 0))
1785                 {
1786                         pfree(rawname);
1787                         freeList(namelist);
1788                         return false;
1789                 }
1790         }
1791
1792         pfree(rawname);
1793         freeList(namelist);
1794
1795         return true;
1796 }
1797
1798 /* assign_hook: do extra actions needed when assigning to search_path */
1799 void
1800 assign_search_path(const char *newval)
1801 {
1802         /*
1803          * We mark the path as needing recomputation, but don't do anything until
1804          * it's needed.  This avoids trying to do database access during GUC
1805          * initialization.
1806          */
1807         namespaceSearchPathValid = false;
1808 }
1809
1810 /*
1811  * InitializeSearchPath: initialize module during InitPostgres.
1812  *
1813  * This is called after we are up enough to be able to do catalog lookups.
1814  */
1815 void
1816 InitializeSearchPath(void)
1817 {
1818         if (IsBootstrapProcessingMode())
1819         {
1820                 /*
1821                  * In bootstrap mode, the search path must be 'pg_catalog' so that
1822                  * tables are created in the proper namespace; ignore the GUC setting.
1823                  */
1824                 MemoryContext oldcxt;
1825
1826                 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1827                 namespaceSearchPath = makeListi1(PG_CATALOG_NAMESPACE);
1828                 MemoryContextSwitchTo(oldcxt);
1829                 pathContainsSystemNamespace = true;
1830                 defaultCreationNamespace = PG_CATALOG_NAMESPACE;
1831                 namespaceSearchPathValid = true;
1832                 namespaceUser = GetUserId();
1833         }
1834         else
1835         {
1836                 /*
1837                  * In normal mode, arrange for a callback on any syscache invalidation
1838                  * of pg_namespace rows.
1839                  */
1840                 CacheRegisterSyscacheCallback(NAMESPACEOID,
1841                                                                           NamespaceCallback,
1842                                                                           (Datum) 0);
1843         }
1844 }
1845
1846 /*
1847  * NamespaceCallback
1848  *              Syscache inval callback function
1849  */
1850 static void
1851 NamespaceCallback(Datum arg, Oid relid)
1852 {
1853         /* Force search path to be recomputed on next use */
1854         namespaceSearchPathValid = false;
1855 }
1856
1857 /*
1858  * Fetch the active search path, expressed as a List of OIDs.
1859  *
1860  * NB: caller must treat the list as read-only!
1861  */
1862 List *
1863 fetch_search_path(void)
1864 {
1865         recomputeNamespacePath();
1866         return namespaceSearchPath;
1867 }