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