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