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