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