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