]> granicus.if.org Git - postgresql/blob - src/backend/catalog/namespace.c
Adjust rules for search_path so that pg_catalog is never implicitly
[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.9 2002/04/15 22:33:21 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_proc.h"
31 #include "catalog/pg_shadow.h"
32 #include "lib/stringinfo.h"
33 #include "miscadmin.h"
34 #include "nodes/makefuncs.h"
35 #include "storage/backendid.h"
36 #include "utils/builtins.h"
37 #include "utils/fmgroids.h"
38 #include "utils/guc.h"
39 #include "utils/catcache.h"
40 #include "utils/lsyscache.h"
41 #include "utils/syscache.h"
42
43
44 /*
45  * The namespace search path is a possibly-empty list of namespace OIDs.
46  * In addition to the explicit list, the TEMP table namespace is always
47  * implicitly searched first (if it's been initialized).  Also, the system
48  * catalog namespace is always searched.  If the system namespace is
49  * explicitly present in the path then it will be searched in the specified
50  * order; otherwise it will be searched after TEMP tables and *before* the
51  * explicit list.  (It might seem that the system namespace should be
52  * implicitly last, but this behavior appears to be required by SQL99.
53  * Also, this provides a way to search the system namespace first without
54  * thereby making it the default creation target namespace.)
55  *
56  * The default creation target namespace is kept equal to the first element
57  * of the (explicit) list.  If the list is empty, there is no default target.
58  *
59  * In bootstrap mode, the search path is set equal to 'pg_catalog', so that
60  * the system namespace is the only one searched or inserted into.
61  * The initdb script is also careful to set search_path to 'pg_catalog' for
62  * its post-bootstrap standalone backend runs.  Otherwise the default search
63  * path is determined by GUC.  The factory default path contains the PUBLIC
64  * namespace (if it exists), preceded by the user's personal namespace
65  * (if one exists).
66  */
67
68 static List *namespaceSearchPath = NIL;
69
70 /* this flag must be updated correctly when namespaceSearchPath is changed */
71 static bool pathContainsSystemNamespace = false;
72
73 /* default place to create stuff; if InvalidOid, no default */
74 static Oid      defaultCreationNamespace = InvalidOid;
75
76 /*
77  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
78  * in a particular backend session (this happens when a CREATE TEMP TABLE
79  * command is first executed).  Thereafter it's the OID of the temp namespace.
80  */
81 static Oid      myTempNamespace = InvalidOid;
82
83 /*
84  * This is the text equivalent of the search path --- it's the value
85  * of the GUC variable 'search_path'.
86  */
87 char *namespace_search_path = NULL;
88
89
90 /*
91  * Deletion ordering constraint item.
92  */
93 typedef struct DelConstraint
94 {
95         Oid                     referencer;             /* table to delete first */
96         Oid                     referencee;             /* table to delete second */
97         int                     pred;                   /* workspace for TopoSortRels */
98         struct DelConstraint *link;     /* workspace for TopoSortRels */
99 } DelConstraint;
100
101
102 /* Local functions */
103 static Oid      GetTempTableNamespace(void);
104 static void RemoveTempRelations(Oid tempNamespaceId);
105 static List *FindTempRelations(Oid tempNamespaceId);
106 static List *FindDeletionConstraints(List *relOids);
107 static List *TopoSortRels(List *relOids, List *constraintList);
108 static void RemoveTempRelationsCallback(void);
109
110
111 /*
112  * RangeVarGetRelid
113  *              Given a RangeVar describing an existing relation,
114  *              select the proper namespace and look up the relation OID.
115  *
116  * If the relation is not found, return InvalidOid if failOK = true,
117  * otherwise raise an error.
118  */
119 Oid
120 RangeVarGetRelid(const RangeVar *relation, bool failOK)
121 {
122         Oid                     namespaceId;
123         Oid                     relId;
124
125         /*
126          * We check the catalog name and then ignore it.
127          */
128         if (relation->catalogname)
129         {
130                 if (strcmp(relation->catalogname, DatabaseName) != 0)
131                         elog(ERROR, "Cross-database references are not implemented");
132         }
133
134         if (relation->schemaname)
135         {
136                 /* use exact schema given */
137                 namespaceId = GetSysCacheOid(NAMESPACENAME,
138                                                                          CStringGetDatum(relation->schemaname),
139                                                                          0, 0, 0);
140                 if (!OidIsValid(namespaceId))
141                         elog(ERROR, "Namespace \"%s\" does not exist",
142                                  relation->schemaname);
143                 relId = get_relname_relid(relation->relname, namespaceId);
144         }
145         else
146         {
147                 /* search the namespace path */
148                 relId = RelnameGetRelid(relation->relname);
149         }
150
151         if (!OidIsValid(relId) && !failOK)
152         {
153                 if (relation->schemaname)
154                         elog(ERROR, "Relation \"%s\".\"%s\" does not exist",
155                                  relation->schemaname, relation->relname);
156                 else
157                         elog(ERROR, "Relation \"%s\" does not exist",
158                                  relation->relname);
159         }
160         return relId;
161 }
162
163 /*
164  * RangeVarGetCreationNamespace
165  *              Given a RangeVar describing a to-be-created relation,
166  *              choose which namespace to create it in.
167  *
168  * Note: calling this may result in a CommandCounterIncrement operation.
169  * That will happen on the first request for a temp table in any particular
170  * backend run; we will need to either create or clean out the temp schema.
171  */
172 Oid
173 RangeVarGetCreationNamespace(const RangeVar *newRelation)
174 {
175         Oid                     namespaceId;
176
177         /*
178          * We check the catalog name and then ignore it.
179          */
180         if (newRelation->catalogname)
181         {
182                 if (strcmp(newRelation->catalogname, DatabaseName) != 0)
183                         elog(ERROR, "Cross-database references are not implemented");
184         }
185
186         if (newRelation->istemp)
187         {
188                 /* TEMP tables are created in our backend-local temp namespace */
189                 if (newRelation->schemaname)
190                         elog(ERROR, "TEMP tables may not specify a namespace");
191                 /* Initialize temp namespace if first time through */
192                 if (!OidIsValid(myTempNamespace))
193                         myTempNamespace = GetTempTableNamespace();
194                 return myTempNamespace;
195         }
196
197         if (newRelation->schemaname)
198         {
199                 /* use exact schema given */
200                 namespaceId = GetSysCacheOid(NAMESPACENAME,
201                                                                          CStringGetDatum(newRelation->schemaname),
202                                                                          0, 0, 0);
203                 if (!OidIsValid(namespaceId))
204                         elog(ERROR, "Namespace \"%s\" does not exist",
205                                  newRelation->schemaname);
206         }
207         else
208         {
209                 /* use the default creation namespace */
210                 namespaceId = defaultCreationNamespace;
211                 if (!OidIsValid(namespaceId))
212                         elog(ERROR, "No namespace has been selected to create in");
213         }
214
215         return namespaceId;
216 }
217
218 /*
219  * RelnameGetRelid
220  *              Try to resolve an unqualified relation name.
221  *              Returns OID if relation found in search path, else InvalidOid.
222  */
223 Oid
224 RelnameGetRelid(const char *relname)
225 {
226         Oid                     relid;
227         List       *lptr;
228
229         /*
230          * If a TEMP-table namespace has been set up, it is implicitly first
231          * in the search path.
232          */
233         if (OidIsValid(myTempNamespace))
234         {
235                 relid = get_relname_relid(relname, myTempNamespace);
236                 if (OidIsValid(relid))
237                         return relid;
238         }
239
240         /*
241          * If system namespace is not in path, implicitly search it before path
242          */
243         if (!pathContainsSystemNamespace)
244         {
245                 relid = get_relname_relid(relname, PG_CATALOG_NAMESPACE);
246                 if (OidIsValid(relid))
247                         return relid;
248         }
249
250         /*
251          * Else search the path
252          */
253         foreach(lptr, namespaceSearchPath)
254         {
255                 Oid                     namespaceId = (Oid) lfirsti(lptr);
256
257                 relid = get_relname_relid(relname, namespaceId);
258                 if (OidIsValid(relid))
259                         return relid;
260         }
261
262         /* Not found in path */
263         return InvalidOid;
264 }
265
266 /*
267  * TypenameGetTypid
268  *              Try to resolve an unqualified datatype name.
269  *              Returns OID if type found in search path, else InvalidOid.
270  *
271  * This is essentially the same as RelnameGetRelid, but we never search
272  * the TEMP table namespace --- there is no reason to refer to the types
273  * of temp tables, AFAICS.
274  */
275 Oid
276 TypenameGetTypid(const char *typname)
277 {
278         Oid                     typid;
279         List       *lptr;
280
281         /*
282          * If system namespace is not in path, implicitly search it before path
283          */
284         if (!pathContainsSystemNamespace)
285         {
286                 typid = GetSysCacheOid(TYPENAMENSP,
287                                                            PointerGetDatum(typname),
288                                                            ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
289                                                            0, 0);
290                 if (OidIsValid(typid))
291                         return typid;
292         }
293
294         /*
295          * Else search the path
296          */
297         foreach(lptr, namespaceSearchPath)
298         {
299                 Oid                     namespaceId = (Oid) lfirsti(lptr);
300
301                 typid = GetSysCacheOid(TYPENAMENSP,
302                                                            PointerGetDatum(typname),
303                                                            ObjectIdGetDatum(namespaceId),
304                                                            0, 0);
305                 if (OidIsValid(typid))
306                         return typid;
307         }
308
309         /* Not found in path */
310         return InvalidOid;
311 }
312
313 /*
314  * FuncnameGetCandidates
315  *              Given a possibly-qualified function name and argument count,
316  *              retrieve a list of the possible matches.
317  *
318  * We search a single namespace if the function name is qualified, else
319  * all namespaces in the search path.  The return list will never contain
320  * multiple entries with identical argument types --- in the multiple-
321  * namespace case, we arrange for entries in earlier namespaces to mask
322  * identical entries in later namespaces.
323  */
324 FuncCandidateList
325 FuncnameGetCandidates(List *names, int nargs)
326 {
327         FuncCandidateList resultList = NULL;
328         char       *catalogname;
329         char       *schemaname = NULL;
330         char       *funcname = NULL;
331         Oid                     namespaceId;
332         CatCList   *catlist;
333         int                     i;
334
335         /* deconstruct the name list */
336         switch (length(names))
337         {
338                 case 1:
339                         funcname = strVal(lfirst(names));
340                         break;
341                 case 2:
342                         schemaname = strVal(lfirst(names));
343                         funcname = strVal(lsecond(names));
344                         break;
345                 case 3:
346                         catalogname = strVal(lfirst(names));
347                         schemaname = strVal(lsecond(names));
348                         funcname = strVal(lfirst(lnext(lnext(names))));
349                         /*
350                          * We check the catalog name and then ignore it.
351                          */
352                         if (strcmp(catalogname, DatabaseName) != 0)
353                                 elog(ERROR, "Cross-database references are not implemented");
354                         break;
355                 default:
356                         elog(ERROR, "Improper qualified name (too many dotted names)");
357                         break;
358         }
359
360         if (schemaname)
361         {
362                 /* use exact schema given */
363                 namespaceId = GetSysCacheOid(NAMESPACENAME,
364                                                                          CStringGetDatum(schemaname),
365                                                                          0, 0, 0);
366                 if (!OidIsValid(namespaceId))
367                         elog(ERROR, "Namespace \"%s\" does not exist",
368                                  schemaname);
369         }
370         else
371         {
372                 /* flag to indicate we need namespace search */
373                 namespaceId = InvalidOid;
374         }
375
376         /* Search syscache by name and nargs only */
377         catlist = SearchSysCacheList(PROCNAMENSP, 2,
378                                                                  CStringGetDatum(funcname),
379                                                                  Int16GetDatum(nargs),
380                                                                  0, 0);
381
382         for (i = 0; i < catlist->n_members; i++)
383         {
384                 HeapTuple       proctup = &catlist->members[i]->tuple;
385                 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
386                 int                     pathpos = 0;
387                 FuncCandidateList newResult;
388
389                 if (OidIsValid(namespaceId))
390                 {
391                         /* Consider only procs in specified namespace */
392                         if (procform->pronamespace != namespaceId)
393                                 continue;
394                         /* No need to check args, they must all be different */
395                 }
396                 else
397                 {
398                         /* Consider only procs that are in the search path */
399                         if (pathContainsSystemNamespace ||
400                                 !IsSystemNamespace(procform->pronamespace))
401                         {
402                                 List       *nsp;
403
404                                 foreach(nsp, namespaceSearchPath)
405                                 {
406                                         pathpos++;
407                                         if (procform->pronamespace == (Oid) lfirsti(nsp))
408                                                 break;
409                                 }
410                                 if (nsp == NIL)
411                                         continue;       /* proc is not in search path */
412                         }
413
414                         /*
415                          * Okay, it's in the search path, but does it have the same
416                          * arguments as something we already accepted?  If so, keep
417                          * only the one that appears earlier in the search path.
418                          *
419                          * If we have an ordered list from SearchSysCacheList (the
420                          * normal case), then any conflicting proc must immediately
421                          * adjoin this one in the list, so we only need to look at
422                          * the newest result item.  If we have an unordered list,
423                          * we have to scan the whole result list.
424                          */
425                         if (resultList)
426                         {
427                                 FuncCandidateList       prevResult;
428
429                                 if (catlist->ordered)
430                                 {
431                                         if (memcmp(procform->proargtypes, resultList->args,
432                                                            nargs * sizeof(Oid)) == 0)
433                                                 prevResult = resultList;
434                                         else
435                                                 prevResult = NULL;
436                                 }
437                                 else
438                                 {
439                                         for (prevResult = resultList;
440                                                  prevResult;
441                                                  prevResult = prevResult->next)
442                                         {
443                                                 if (memcmp(procform->proargtypes, prevResult->args,
444                                                                    nargs * sizeof(Oid)) == 0)
445                                                         break;
446                                         }
447                                 }
448                                 if (prevResult)
449                                 {
450                                         /* We have a match with a previous result */
451                                         Assert(pathpos != prevResult->pathpos);
452                                         if (pathpos > prevResult->pathpos)
453                                                 continue; /* keep previous result */
454                                         /* replace previous result */
455                                         prevResult->pathpos = pathpos;
456                                         prevResult->oid = proctup->t_data->t_oid;
457                                         continue;       /* args are same, of course */
458                                 }
459                         }
460                 }
461
462                 /*
463                  * Okay to add it to result list
464                  */
465                 newResult = (FuncCandidateList)
466                         palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
467                                    + nargs * sizeof(Oid));
468                 newResult->pathpos = pathpos;
469                 newResult->oid = proctup->t_data->t_oid;
470                 memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid));
471
472                 newResult->next = resultList;
473                 resultList = newResult;
474         }
475
476         ReleaseSysCacheList(catlist);
477
478         return resultList;
479 }
480
481 /*
482  * QualifiedNameGetCreationNamespace
483  *              Given a possibly-qualified name for an object (in List-of-Values
484  *              format), determine what namespace the object should be created in.
485  *              Also extract and return the object name (last component of list).
486  *
487  * This is *not* used for tables.  Hence, the TEMP table namespace is
488  * never selected as the creation target.
489  */
490 Oid
491 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
492 {
493         char       *catalogname;
494         char       *schemaname = NULL;
495         char       *objname = NULL;
496         Oid                     namespaceId;
497
498         /* deconstruct the name list */
499         switch (length(names))
500         {
501                 case 1:
502                         objname = strVal(lfirst(names));
503                         break;
504                 case 2:
505                         schemaname = strVal(lfirst(names));
506                         objname = strVal(lsecond(names));
507                         break;
508                 case 3:
509                         catalogname = strVal(lfirst(names));
510                         schemaname = strVal(lsecond(names));
511                         objname = strVal(lfirst(lnext(lnext(names))));
512                         /*
513                          * We check the catalog name and then ignore it.
514                          */
515                         if (strcmp(catalogname, DatabaseName) != 0)
516                                 elog(ERROR, "Cross-database references are not implemented");
517                         break;
518                 default:
519                         elog(ERROR, "Improper qualified name (too many dotted names)");
520                         break;
521         }
522
523         if (schemaname)
524         {
525                 /* use exact schema given */
526                 namespaceId = GetSysCacheOid(NAMESPACENAME,
527                                                                          CStringGetDatum(schemaname),
528                                                                          0, 0, 0);
529                 if (!OidIsValid(namespaceId))
530                         elog(ERROR, "Namespace \"%s\" does not exist",
531                                  schemaname);
532         }
533         else
534         {
535                 /* use the default creation namespace */
536                 namespaceId = defaultCreationNamespace;
537                 if (!OidIsValid(namespaceId))
538                         elog(ERROR, "No namespace has been selected to create in");
539         }
540
541         *objname_p = objname;
542         return namespaceId;
543 }
544
545 /*
546  * makeRangeVarFromNameList
547  *              Utility routine to convert a qualified-name list into RangeVar form.
548  */
549 RangeVar *
550 makeRangeVarFromNameList(List *names)
551 {
552         RangeVar   *rel = makeRangeVar(NULL, NULL);
553
554         switch (length(names))
555         {
556                 case 1:
557                         rel->relname = strVal(lfirst(names));
558                         break;
559                 case 2:
560                         rel->schemaname = strVal(lfirst(names));
561                         rel->relname = strVal(lsecond(names));
562                         break;
563                 case 3:
564                         rel->catalogname = strVal(lfirst(names));
565                         rel->schemaname = strVal(lsecond(names));
566                         rel->relname = strVal(lfirst(lnext(lnext(names))));
567                         break;
568                 default:
569                         elog(ERROR, "Improper relation name (too many dotted names)");
570                         break;
571         }
572
573         return rel;
574 }
575
576 /*
577  * NameListToString
578  *              Utility routine to convert a qualified-name list into a string.
579  *              Used primarily to form error messages.
580  */
581 char *
582 NameListToString(List *names)
583 {
584         StringInfoData string;
585         List            *l;
586
587         initStringInfo(&string);
588
589         foreach(l, names)
590         {
591                 if (l != names)
592                         appendStringInfoChar(&string, '.');
593                 appendStringInfo(&string, "%s", strVal(lfirst(l)));
594         }
595
596         return string.data;
597 }
598
599 /*
600  * isTempNamespace - is the given namespace my temporary-table namespace?
601  */
602 bool
603 isTempNamespace(Oid namespaceId)
604 {
605         if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
606                 return true;
607         return false;
608 }
609
610 /*
611  * GetTempTableNamespace
612  *              Initialize temp table namespace on first use in a particular backend
613  */
614 static Oid
615 GetTempTableNamespace(void)
616 {
617         char            namespaceName[NAMEDATALEN];
618         Oid                     namespaceId;
619
620         snprintf(namespaceName, NAMEDATALEN, "pg_temp_%d", MyBackendId);
621
622         namespaceId = GetSysCacheOid(NAMESPACENAME,
623                                                                  CStringGetDatum(namespaceName),
624                                                                  0, 0, 0);
625         if (!OidIsValid(namespaceId))
626         {
627                 /*
628                  * First use of this temp namespace in this database; create it.
629                  * The temp namespaces are always owned by the superuser.
630                  */
631                 namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID);
632                 /* Advance command counter to make namespace visible */
633                 CommandCounterIncrement();
634         }
635         else
636         {
637                 /*
638                  * If the namespace already exists, clean it out (in case the
639                  * former owner crashed without doing so).
640                  */
641                 RemoveTempRelations(namespaceId);
642         }
643
644         /*
645          * Register exit callback to clean out temp tables at backend shutdown.
646          */
647         on_shmem_exit(RemoveTempRelationsCallback, 0);
648
649         return namespaceId;
650 }
651
652 /*
653  * Remove all relations in the specified temp namespace.
654  *
655  * This is called at backend shutdown (if we made any temp relations).
656  * It is also called when we begin using a pre-existing temp namespace,
657  * in order to clean out any relations that might have been created by
658  * a crashed backend.
659  */
660 static void
661 RemoveTempRelations(Oid tempNamespaceId)
662 {
663         List       *tempRelList;
664         List       *constraintList;
665         List       *lptr;
666
667         /* Get a list of relations to delete */
668         tempRelList = FindTempRelations(tempNamespaceId);
669
670         if (tempRelList == NIL)
671                 return;                                 /* nothing to do */
672
673         /* If more than one, sort them to respect any deletion-order constraints */
674         if (length(tempRelList) > 1)
675         {
676                 constraintList = FindDeletionConstraints(tempRelList);
677                 if (constraintList != NIL)
678                         tempRelList = TopoSortRels(tempRelList, constraintList);
679         }
680
681         /* Scan the list and delete all entries */
682         foreach(lptr, tempRelList)
683         {
684                 Oid                     reloid = (Oid) lfirsti(lptr);
685
686                 heap_drop_with_catalog(reloid, true);
687                 /*
688                  * Advance cmd counter to make catalog changes visible, in case
689                  * a later entry depends on this one.
690                  */
691                 CommandCounterIncrement();
692         }
693 }
694
695 /*
696  * Find all relations in the specified temp namespace.
697  *
698  * Returns a list of relation OIDs.
699  */
700 static List *
701 FindTempRelations(Oid tempNamespaceId)
702 {
703         List       *tempRelList = NIL;
704         Relation        pgclass;
705         HeapScanDesc scan;
706         HeapTuple       tuple;
707         ScanKeyData key;
708
709         /*
710          * Scan pg_class to find all the relations in the target namespace.
711          * Ignore indexes, though, on the assumption that they'll go away
712          * when their tables are deleted.
713          */
714         ScanKeyEntryInitialize(&key, 0x0,
715                                                    Anum_pg_class_relnamespace,
716                                                    F_OIDEQ,
717                                                    ObjectIdGetDatum(tempNamespaceId));
718
719         pgclass = heap_openr(RelationRelationName, AccessShareLock);
720         scan = heap_beginscan(pgclass, false, SnapshotNow, 1, &key);
721
722         while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
723         {
724                 switch (((Form_pg_class) GETSTRUCT(tuple))->relkind)
725                 {
726                         case RELKIND_RELATION:
727                         case RELKIND_SEQUENCE:
728                         case RELKIND_VIEW:
729                                 tempRelList = lconsi(tuple->t_data->t_oid, tempRelList);
730                                 break;
731                         default:
732                                 break;
733                 }
734         }
735
736         heap_endscan(scan);
737         heap_close(pgclass, AccessShareLock);
738
739         return tempRelList;
740 }
741
742 /*
743  * Find deletion-order constraints involving the given relation OIDs.
744  *
745  * Returns a list of DelConstraint objects.
746  */
747 static List *
748 FindDeletionConstraints(List *relOids)
749 {
750         List       *constraintList = NIL;
751         Relation        inheritsrel;
752         HeapScanDesc scan;
753         HeapTuple       tuple;
754
755         /*
756          * Scan pg_inherits to find parents and children that are in the list.
757          */
758         inheritsrel = heap_openr(InheritsRelationName, AccessShareLock);
759         scan = heap_beginscan(inheritsrel, 0, SnapshotNow, 0, NULL);
760
761         while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
762         {
763                 Oid             inhrelid = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid;
764                 Oid             inhparent = ((Form_pg_inherits) GETSTRUCT(tuple))->inhparent;
765
766                 if (intMember(inhrelid, relOids) && intMember(inhparent, relOids))
767                 {
768                         DelConstraint  *item;
769
770                         item = (DelConstraint *) palloc(sizeof(DelConstraint));
771                         item->referencer = inhrelid;
772                         item->referencee = inhparent;
773                         constraintList = lcons(item, constraintList);
774                 }
775         }
776
777         heap_endscan(scan);
778         heap_close(inheritsrel, AccessShareLock);
779
780         return constraintList;
781 }
782
783 /*
784  * TopoSortRels -- topological sort of a list of rels to delete
785  *
786  * This is a lot simpler and slower than, for example, the topological sort
787  * algorithm shown in Knuth's Volume 1.  However, we are not likely to be
788  * working with more than a few constraints, so the apparent slowness of the
789  * algorithm won't really matter.
790  */
791 static List *
792 TopoSortRels(List *relOids, List *constraintList)
793 {
794         int                     queue_size = length(relOids);
795         Oid                *rels;
796         int                *beforeConstraints;
797         DelConstraint **afterConstraints;
798         List       *resultList = NIL;
799         List       *lptr;
800         int                     i,
801                                 j,
802                                 k,
803                                 last;
804
805         /* Allocate workspace */
806         rels = (Oid *) palloc(queue_size * sizeof(Oid));
807         beforeConstraints = (int *) palloc(queue_size * sizeof(int));
808         afterConstraints = (DelConstraint **)
809                 palloc(queue_size * sizeof(DelConstraint*));
810
811         /* Build an array of the target relation OIDs */
812         i = 0;
813         foreach(lptr, relOids)
814         {
815                 rels[i++] = (Oid) lfirsti(lptr);
816         }
817
818         /*
819          * Scan the constraints, and for each rel in the array, generate a
820          * count of the number of constraints that say it must be before
821          * something else, plus a list of the constraints that say it must be
822          * after something else. The count for the j'th rel is stored in
823          * beforeConstraints[j], and the head of its list in
824          * afterConstraints[j].  Each constraint stores its list link in
825          * its link field (note any constraint will be in just one list).
826          * The array index for the before-rel of each constraint is
827          * remembered in the constraint's pred field.
828          */
829         MemSet(beforeConstraints, 0, queue_size * sizeof(int));
830         MemSet(afterConstraints, 0, queue_size * sizeof(DelConstraint*));
831         foreach(lptr, constraintList)
832         {
833                 DelConstraint  *constraint = (DelConstraint *) lfirst(lptr);
834                 Oid                     rel;
835
836                 /* Find the referencer rel in the array */
837                 rel = constraint->referencer;
838                 for (j = queue_size; --j >= 0;)
839                 {
840                         if (rels[j] == rel)
841                                 break;
842                 }
843                 Assert(j >= 0);                 /* should have found a match */
844                 /* Find the referencee rel in the array */
845                 rel = constraint->referencee;
846                 for (k = queue_size; --k >= 0;)
847                 {
848                         if (rels[k] == rel)
849                                 break;
850                 }
851                 Assert(k >= 0);                 /* should have found a match */
852                 beforeConstraints[j]++; /* referencer must come before */
853                 /* add this constraint to list of after-constraints for referencee */
854                 constraint->pred = j;
855                 constraint->link = afterConstraints[k];
856                 afterConstraints[k] = constraint;
857         }
858         /*--------------------
859          * Now scan the rels array backwards.   At each step, output the
860          * last rel that has no remaining before-constraints, and decrease
861          * the beforeConstraints count of each of the rels it was constrained
862          * against.  (This is the right order since we are building the result
863          * list back-to-front.)
864          * i = counter for number of rels left to output
865          * j = search index for rels[]
866          * dc = temp for scanning constraint list for rel j
867          * last = last valid index in rels (avoid redundant searches)
868          *--------------------
869          */
870         last = queue_size - 1;
871         for (i = queue_size; --i >= 0;)
872         {
873                 DelConstraint  *dc;
874
875                 /* Find next candidate to output */
876                 while (rels[last] == InvalidOid)
877                         last--;
878                 for (j = last; j >= 0; j--)
879                 {
880                         if (rels[j] != InvalidOid && beforeConstraints[j] == 0)
881                                 break;
882                 }
883                 /* If no available candidate, topological sort fails */
884                 if (j < 0)
885                         elog(ERROR, "TopoSortRels: failed to find a workable deletion ordering");
886                 /* Output candidate, and mark it done by zeroing rels[] entry */
887                 resultList = lconsi(rels[j], resultList);
888                 rels[j] = InvalidOid;
889                 /* Update beforeConstraints counts of its predecessors */
890                 for (dc = afterConstraints[j]; dc; dc = dc->link)
891                         beforeConstraints[dc->pred]--;
892         }
893
894         /* Done */
895         return resultList;
896 }
897
898 /*
899  * Callback to remove temp relations at backend exit.
900  */
901 static void
902 RemoveTempRelationsCallback(void)
903 {
904         if (OidIsValid(myTempNamespace)) /* should always be true */
905         {
906                 /* Need to ensure we have a usable transaction. */
907                 AbortOutOfAnyTransaction();
908                 StartTransactionCommand();
909
910                 RemoveTempRelations(myTempNamespace);
911
912                 CommitTransactionCommand();
913         }
914 }
915
916 /*
917  * Routines for handling the GUC variable 'search_path'.
918  */
919
920 /* parse_hook: is proposed value valid? */
921 bool
922 check_search_path(const char *proposed)
923 {
924         char       *rawname;
925         List       *namelist;
926         List       *l;
927
928         /* Need a modifiable copy of string */
929         rawname = pstrdup(proposed);
930
931         /* Parse string into list of identifiers */
932         if (!SplitIdentifierString(rawname, ',', &namelist))
933         {
934                 /* syntax error in name list */
935                 pfree(rawname);
936                 freeList(namelist);
937                 return false;
938         }
939
940         /*
941          * If we aren't inside a transaction, we cannot do database access so
942          * cannot verify the individual names.  Must accept the list on faith.
943          * (This case can happen, for example, when the postmaster reads a
944          * search_path setting from postgresql.conf.)
945          */
946         if (!IsTransactionState())
947         {
948                 pfree(rawname);
949                 freeList(namelist);
950                 return true;
951         }
952
953         /*
954          * Verify that all the names are either valid namespace names or "$user".
955          * (We do not require $user to correspond to a valid namespace; should we?)
956          */
957         foreach(l, namelist)
958         {
959                 char   *curname = (char *) lfirst(l);
960
961                 if (strcmp(curname, "$user") == 0)
962                         continue;
963                 if (!SearchSysCacheExists(NAMESPACENAME,
964                                                                   CStringGetDatum(curname),
965                                                                   0, 0, 0))
966                 {
967                         pfree(rawname);
968                         freeList(namelist);
969                         return false;
970                 }
971         }
972
973         pfree(rawname);
974         freeList(namelist);
975
976         return true;
977 }
978
979 /* assign_hook: do extra actions needed when assigning to search_path */
980 void
981 assign_search_path(const char *newval)
982 {
983         char       *rawname;
984         List       *namelist;
985         List       *oidlist;
986         List       *newpath;
987         List       *l;
988         MemoryContext oldcxt;
989
990         /*
991          * If we aren't inside a transaction, we cannot do database access so
992          * cannot look up the names.  In this case, do nothing; the internal
993          * search path will be fixed later by InitializeSearchPath.  (We assume
994          * this situation can only happen in the postmaster or early in backend
995          * startup.)
996          */
997         if (!IsTransactionState())
998                 return;
999
1000         /* Need a modifiable copy of string */
1001         rawname = pstrdup(newval);
1002
1003         /* Parse string into list of identifiers */
1004         if (!SplitIdentifierString(rawname, ',', &namelist))
1005         {
1006                 /* syntax error in name list */
1007                 /* this should not happen if GUC checked check_search_path */
1008                 elog(ERROR, "assign_search_path: invalid list syntax");
1009         }
1010
1011         /*
1012          * Convert the list of names to a list of OIDs.  If any names are not
1013          * recognizable, just leave them out of the list.  (This is our only
1014          * reasonable recourse when the already-accepted default is bogus.)
1015          */
1016         oidlist = NIL;
1017         foreach(l, namelist)
1018         {
1019                 char   *curname = (char *) lfirst(l);
1020                 Oid             namespaceId;
1021
1022                 if (strcmp(curname, "$user") == 0)
1023                 {
1024                         /* $user --- substitute namespace matching user name, if any */
1025                         HeapTuple       tuple;
1026
1027                         tuple = SearchSysCache(SHADOWSYSID,
1028                                                                    ObjectIdGetDatum(GetSessionUserId()),
1029                                                                    0, 0, 0);
1030                         if (HeapTupleIsValid(tuple))
1031                         {
1032                                 char   *uname;
1033
1034                                 uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
1035                                 namespaceId = GetSysCacheOid(NAMESPACENAME,
1036                                                                                          CStringGetDatum(uname),
1037                                                                                          0, 0, 0);
1038                                 if (OidIsValid(namespaceId))
1039                                         oidlist = lappendi(oidlist, namespaceId);
1040                                 ReleaseSysCache(tuple);
1041                         }
1042                 }
1043                 else
1044                 {
1045                         /* normal namespace reference */
1046                         namespaceId = GetSysCacheOid(NAMESPACENAME,
1047                                                                                  CStringGetDatum(curname),
1048                                                                                  0, 0, 0);
1049                         if (OidIsValid(namespaceId))
1050                                 oidlist = lappendi(oidlist, namespaceId);
1051                 }
1052         }
1053
1054         /*
1055          * Now that we've successfully built the new list of namespace OIDs,
1056          * save it in permanent storage.
1057          */
1058         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1059         newpath = listCopy(oidlist);
1060         MemoryContextSwitchTo(oldcxt);
1061
1062         /* Now safe to assign to state variable. */
1063         freeList(namespaceSearchPath);
1064         namespaceSearchPath = newpath;
1065
1066         /*
1067          * Update info derived from search path.
1068          */
1069         pathContainsSystemNamespace = intMember(PG_CATALOG_NAMESPACE,
1070                                                                                         namespaceSearchPath);
1071
1072         if (namespaceSearchPath == NIL)
1073                 defaultCreationNamespace = InvalidOid;
1074         else
1075                 defaultCreationNamespace = (Oid) lfirsti(namespaceSearchPath);
1076
1077         /* Clean up. */
1078         pfree(rawname);
1079         freeList(namelist);
1080         freeList(oidlist);
1081 }
1082
1083 /*
1084  * InitializeSearchPath: initialize module during InitPostgres.
1085  *
1086  * This is called after we are up enough to be able to do catalog lookups.
1087  */
1088 void
1089 InitializeSearchPath(void)
1090 {
1091         if (IsBootstrapProcessingMode())
1092         {
1093                 /*
1094                  * In bootstrap mode, the search path must be 'pg_catalog' so that
1095                  * tables are created in the proper namespace; ignore the GUC setting.
1096                  */
1097                 MemoryContext oldcxt;
1098
1099                 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1100                 namespaceSearchPath = makeListi1(PG_CATALOG_NAMESPACE);
1101                 MemoryContextSwitchTo(oldcxt);
1102                 pathContainsSystemNamespace = true;
1103                 defaultCreationNamespace = PG_CATALOG_NAMESPACE;
1104         }
1105         else
1106         {
1107                 /*
1108                  * If a search path setting was provided before we were able to
1109                  * execute lookups, establish the internal search path now.
1110                  */
1111                 if (namespace_search_path && *namespace_search_path &&
1112                         namespaceSearchPath == NIL)
1113                         assign_search_path(namespace_search_path);
1114         }
1115 }