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