OSDN Git Service

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