]> granicus.if.org Git - postgresql/blob - src/backend/catalog/namespace.c
Fix plancache so that any required replanning is done with the same
[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-2007, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  * IDENTIFICATION
16  *        $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.93 2007/03/23 19:53:51 tgl Exp $
17  *
18  *-------------------------------------------------------------------------
19  */
20 #include "postgres.h"
21
22 #include "access/xact.h"
23 #include "catalog/dependency.h"
24 #include "catalog/namespace.h"
25 #include "catalog/pg_authid.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_opfamily.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_type.h"
33 #include "commands/dbcommands.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/guc.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, implicitly-searched namespaces
50  * may be included:
51  *
52  * 1. If a TEMP table namespace has been initialized in this session, it
53  * is implicitly searched first.  (The only time this doesn't happen is
54  * when we are obeying an override search path spec that says not to use the
55  * temp namespace, or the temp namespace is included in the explicit list.)
56  *
57  * 2. The system catalog namespace is always searched.  If the system
58  * namespace is present in the explicit path then it will be searched in
59  * the specified order; otherwise it will be searched after TEMP tables and
60  * *before* the explicit list.  (It might seem that the system namespace
61  * should be implicitly last, but this behavior appears to be required by
62  * SQL99.  Also, this provides a way to search the system namespace first
63  * without thereby making it the default creation target namespace.)
64  *
65  * The default creation target namespace is always the first element of the
66  * explicit list.  If the explicit list is empty, there is no default target.
67  *
68  * In bootstrap mode, the search path is set equal to 'pg_catalog', so that
69  * the system namespace is the only one searched or inserted into.
70  * initdb is also careful to set search_path to 'pg_catalog' for its
71  * post-bootstrap standalone backend runs.      Otherwise the default search
72  * path is determined by GUC.  The factory default path contains the PUBLIC
73  * namespace (if it exists), preceded by the user's personal namespace
74  * (if one exists).
75  *
76  * We support a stack of "override" search path settings for use within
77  * specific sections of backend code.  namespace_search_path is ignored
78  * whenever the override stack is nonempty.  activeSearchPath is always
79  * the actually active path; it points either to the search list of the
80  * topmost stack entry, or to baseSearchPath which is the list derived
81  * from namespace_search_path.
82  *
83  * If baseSearchPathValid is false, then baseSearchPath (and other
84  * derived variables) need to be recomputed from namespace_search_path.
85  * We mark it invalid upon an assignment to namespace_search_path or receipt
86  * of a syscache invalidation event for pg_namespace.  The recomputation
87  * is done during the next non-overridden lookup attempt.  Note that an
88  * override spec is never subject to recomputation.
89  *
90  * Any namespaces mentioned in namespace_search_path that are not readable
91  * by the current user ID are simply left out of baseSearchPath; 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  * Note: all data pointed to by these List variables is in TopMemoryContext.
96  */
97
98 /* These variables define the actually active state: */
99
100 static List *activeSearchPath = NIL;
101
102 /* default place to create stuff; if InvalidOid, no default */
103 static Oid      activeCreationNamespace = InvalidOid;
104
105 /* These variables are the values last derived from namespace_search_path: */
106
107 static List *baseSearchPath = NIL;
108
109 static Oid      baseCreationNamespace = InvalidOid;
110
111 static Oid      namespaceUser = InvalidOid;
112
113 /* The above three values are valid only if baseSearchPathValid */
114 static bool baseSearchPathValid = true;
115
116 /* Override requests are remembered in a stack of OverrideStackEntry structs */
117
118 typedef struct
119 {
120         List       *searchPath;                         /* the desired search path */
121         Oid                     creationNamespace;              /* the desired creation namespace */
122         int                     nestLevel;                              /* subtransaction nesting level */
123 } OverrideStackEntry;
124
125 static List *overrideStack = NIL;
126
127 /*
128  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
129  * in a particular backend session (this happens when a CREATE TEMP TABLE
130  * command is first executed).  Thereafter it's the OID of the temp namespace.
131  *
132  * myTempNamespaceSubID shows whether we've created the TEMP namespace in the
133  * current subtransaction.      The flag propagates up the subtransaction tree,
134  * so the main transaction will correctly recognize the flag if all
135  * intermediate subtransactions commit.  When it is InvalidSubTransactionId,
136  * we either haven't made the TEMP namespace yet, or have successfully
137  * committed its creation, depending on whether myTempNamespace is valid.
138  */
139 static Oid      myTempNamespace = InvalidOid;
140
141 static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
142
143 /*
144  * This is the user's textual search path specification --- it's the value
145  * of the GUC variable 'search_path'.
146  */
147 char       *namespace_search_path = NULL;
148
149
150 /* Local functions */
151 static void recomputeNamespacePath(void);
152 static void InitTempTableNamespace(void);
153 static void RemoveTempRelations(Oid tempNamespaceId);
154 static void RemoveTempRelationsCallback(int code, Datum arg);
155 static void NamespaceCallback(Datum arg, Oid relid);
156
157 /* These don't really need to appear in any header file */
158 Datum           pg_table_is_visible(PG_FUNCTION_ARGS);
159 Datum           pg_type_is_visible(PG_FUNCTION_ARGS);
160 Datum           pg_function_is_visible(PG_FUNCTION_ARGS);
161 Datum           pg_operator_is_visible(PG_FUNCTION_ARGS);
162 Datum           pg_opclass_is_visible(PG_FUNCTION_ARGS);
163 Datum           pg_conversion_is_visible(PG_FUNCTION_ARGS);
164 Datum           pg_my_temp_schema(PG_FUNCTION_ARGS);
165 Datum           pg_is_other_temp_schema(PG_FUNCTION_ARGS);
166
167
168 /*
169  * RangeVarGetRelid
170  *              Given a RangeVar describing an existing relation,
171  *              select the proper namespace and look up the relation OID.
172  *
173  * If the relation is not found, return InvalidOid if failOK = true,
174  * otherwise raise an error.
175  */
176 Oid
177 RangeVarGetRelid(const RangeVar *relation, bool failOK)
178 {
179         Oid                     namespaceId;
180         Oid                     relId;
181
182         /*
183          * We check the catalog name and then ignore it.
184          */
185         if (relation->catalogname)
186         {
187                 if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
188                         ereport(ERROR,
189                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
190                                          errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
191                                                         relation->catalogname, relation->schemaname,
192                                                         relation->relname)));
193         }
194
195         if (relation->schemaname)
196         {
197                 /* use exact schema given */
198                 namespaceId = LookupExplicitNamespace(relation->schemaname);
199                 relId = get_relname_relid(relation->relname, namespaceId);
200         }
201         else
202         {
203                 /* search the namespace path */
204                 relId = RelnameGetRelid(relation->relname);
205         }
206
207         if (!OidIsValid(relId) && !failOK)
208         {
209                 if (relation->schemaname)
210                         ereport(ERROR,
211                                         (errcode(ERRCODE_UNDEFINED_TABLE),
212                                          errmsg("relation \"%s.%s\" does not exist",
213                                                         relation->schemaname, relation->relname)));
214                 else
215                         ereport(ERROR,
216                                         (errcode(ERRCODE_UNDEFINED_TABLE),
217                                          errmsg("relation \"%s\" does not exist",
218                                                         relation->relname)));
219         }
220         return relId;
221 }
222
223 /*
224  * RangeVarGetCreationNamespace
225  *              Given a RangeVar describing a to-be-created relation,
226  *              choose which namespace to create it in.
227  *
228  * Note: calling this may result in a CommandCounterIncrement operation.
229  * That will happen on the first request for a temp table in any particular
230  * backend run; we will need to either create or clean out the temp schema.
231  */
232 Oid
233 RangeVarGetCreationNamespace(const RangeVar *newRelation)
234 {
235         Oid                     namespaceId;
236
237         /*
238          * We check the catalog name and then ignore it.
239          */
240         if (newRelation->catalogname)
241         {
242                 if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
243                         ereport(ERROR,
244                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
245                                          errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
246                                                         newRelation->catalogname, newRelation->schemaname,
247                                                         newRelation->relname)));
248         }
249
250         if (newRelation->istemp)
251         {
252                 /* TEMP tables are created in our backend-local temp namespace */
253                 if (newRelation->schemaname)
254                         ereport(ERROR,
255                                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
256                                   errmsg("temporary tables cannot specify a schema name")));
257                 /* Initialize temp namespace if first time through */
258                 if (!OidIsValid(myTempNamespace))
259                         InitTempTableNamespace();
260                 return myTempNamespace;
261         }
262
263         if (newRelation->schemaname)
264         {
265                 /* use exact schema given */
266                 namespaceId = GetSysCacheOid(NAMESPACENAME,
267                                                                          CStringGetDatum(newRelation->schemaname),
268                                                                          0, 0, 0);
269                 if (!OidIsValid(namespaceId))
270                         ereport(ERROR,
271                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
272                                          errmsg("schema \"%s\" does not exist",
273                                                         newRelation->schemaname)));
274                 /* we do not check for USAGE rights here! */
275         }
276         else
277         {
278                 /* use the default creation namespace */
279                 recomputeNamespacePath();
280                 namespaceId = activeCreationNamespace;
281                 if (!OidIsValid(namespaceId))
282                         ereport(ERROR,
283                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
284                                          errmsg("no schema has been selected to create in")));
285         }
286
287         /* Note: callers will check for CREATE rights when appropriate */
288
289         return namespaceId;
290 }
291
292 /*
293  * RelnameGetRelid
294  *              Try to resolve an unqualified relation name.
295  *              Returns OID if relation found in search path, else InvalidOid.
296  */
297 Oid
298 RelnameGetRelid(const char *relname)
299 {
300         Oid                     relid;
301         ListCell   *l;
302
303         recomputeNamespacePath();
304
305         foreach(l, activeSearchPath)
306         {
307                 Oid                     namespaceId = lfirst_oid(l);
308
309                 relid = get_relname_relid(relname, namespaceId);
310                 if (OidIsValid(relid))
311                         return relid;
312         }
313
314         /* Not found in path */
315         return InvalidOid;
316 }
317
318
319 /*
320  * RelationIsVisible
321  *              Determine whether a relation (identified by OID) is visible in the
322  *              current search path.  Visible means "would be found by searching
323  *              for the unqualified relation name".
324  */
325 bool
326 RelationIsVisible(Oid relid)
327 {
328         HeapTuple       reltup;
329         Form_pg_class relform;
330         Oid                     relnamespace;
331         bool            visible;
332
333         reltup = SearchSysCache(RELOID,
334                                                         ObjectIdGetDatum(relid),
335                                                         0, 0, 0);
336         if (!HeapTupleIsValid(reltup))
337                 elog(ERROR, "cache lookup failed for relation %u", relid);
338         relform = (Form_pg_class) GETSTRUCT(reltup);
339
340         recomputeNamespacePath();
341
342         /*
343          * Quick check: if it ain't in the path at all, it ain't visible. Items in
344          * the system namespace are surely in the path and so we needn't even do
345          * list_member_oid() for them.
346          */
347         relnamespace = relform->relnamespace;
348         if (relnamespace != PG_CATALOG_NAMESPACE &&
349                 !list_member_oid(activeSearchPath, relnamespace))
350                 visible = false;
351         else
352         {
353                 /*
354                  * If it is in the path, it might still not be visible; it could be
355                  * hidden by another relation of the same name earlier in the path. So
356                  * we must do a slow check for conflicting relations.
357                  */
358                 char       *relname = NameStr(relform->relname);
359                 ListCell   *l;
360
361                 visible = false;
362                 foreach(l, activeSearchPath)
363                 {
364                         Oid                     namespaceId = lfirst_oid(l);
365
366                         if (namespaceId == relnamespace)
367                         {
368                                 /* Found it first in path */
369                                 visible = true;
370                                 break;
371                         }
372                         if (OidIsValid(get_relname_relid(relname, namespaceId)))
373                         {
374                                 /* Found something else first in path */
375                                 break;
376                         }
377                 }
378         }
379
380         ReleaseSysCache(reltup);
381
382         return visible;
383 }
384
385
386 /*
387  * TypenameGetTypid
388  *              Try to resolve an unqualified datatype name.
389  *              Returns OID if type found in search path, else InvalidOid.
390  *
391  * This is essentially the same as RelnameGetRelid.
392  */
393 Oid
394 TypenameGetTypid(const char *typname)
395 {
396         Oid                     typid;
397         ListCell   *l;
398
399         recomputeNamespacePath();
400
401         foreach(l, activeSearchPath)
402         {
403                 Oid                     namespaceId = lfirst_oid(l);
404
405                 typid = GetSysCacheOid(TYPENAMENSP,
406                                                            PointerGetDatum(typname),
407                                                            ObjectIdGetDatum(namespaceId),
408                                                            0, 0);
409                 if (OidIsValid(typid))
410                         return typid;
411         }
412
413         /* Not found in path */
414         return InvalidOid;
415 }
416
417 /*
418  * TypeIsVisible
419  *              Determine whether a type (identified by OID) is visible in the
420  *              current search path.  Visible means "would be found by searching
421  *              for the unqualified type name".
422  */
423 bool
424 TypeIsVisible(Oid typid)
425 {
426         HeapTuple       typtup;
427         Form_pg_type typform;
428         Oid                     typnamespace;
429         bool            visible;
430
431         typtup = SearchSysCache(TYPEOID,
432                                                         ObjectIdGetDatum(typid),
433                                                         0, 0, 0);
434         if (!HeapTupleIsValid(typtup))
435                 elog(ERROR, "cache lookup failed for type %u", typid);
436         typform = (Form_pg_type) GETSTRUCT(typtup);
437
438         recomputeNamespacePath();
439
440         /*
441          * Quick check: if it ain't in the path at all, it ain't visible. Items in
442          * the system namespace are surely in the path and so we needn't even do
443          * list_member_oid() for them.
444          */
445         typnamespace = typform->typnamespace;
446         if (typnamespace != PG_CATALOG_NAMESPACE &&
447                 !list_member_oid(activeSearchPath, typnamespace))
448                 visible = false;
449         else
450         {
451                 /*
452                  * If it is in the path, it might still not be visible; it could be
453                  * hidden by another type of the same name earlier in the path. So we
454                  * must do a slow check for conflicting types.
455                  */
456                 char       *typname = NameStr(typform->typname);
457                 ListCell   *l;
458
459                 visible = false;
460                 foreach(l, activeSearchPath)
461                 {
462                         Oid                     namespaceId = lfirst_oid(l);
463
464                         if (namespaceId == typnamespace)
465                         {
466                                 /* Found it first in path */
467                                 visible = true;
468                                 break;
469                         }
470                         if (SearchSysCacheExists(TYPENAMENSP,
471                                                                          PointerGetDatum(typname),
472                                                                          ObjectIdGetDatum(namespaceId),
473                                                                          0, 0))
474                         {
475                                 /* Found something else first in path */
476                                 break;
477                         }
478                 }
479         }
480
481         ReleaseSysCache(typtup);
482
483         return visible;
484 }
485
486
487 /*
488  * FuncnameGetCandidates
489  *              Given a possibly-qualified function name and argument count,
490  *              retrieve a list of the possible matches.
491  *
492  * If nargs is -1, we return all functions matching the given name,
493  * regardless of argument count.
494  *
495  * We search a single namespace if the function name is qualified, else
496  * all namespaces in the search path.  The return list will never contain
497  * multiple entries with identical argument lists --- in the multiple-
498  * namespace case, we arrange for entries in earlier namespaces to mask
499  * identical entries in later namespaces.
500  */
501 FuncCandidateList
502 FuncnameGetCandidates(List *names, int nargs)
503 {
504         FuncCandidateList resultList = NULL;
505         char       *schemaname;
506         char       *funcname;
507         Oid                     namespaceId;
508         CatCList   *catlist;
509         int                     i;
510
511         /* deconstruct the name list */
512         DeconstructQualifiedName(names, &schemaname, &funcname);
513
514         if (schemaname)
515         {
516                 /* use exact schema given */
517                 namespaceId = LookupExplicitNamespace(schemaname);
518         }
519         else
520         {
521                 /* flag to indicate we need namespace search */
522                 namespaceId = InvalidOid;
523                 recomputeNamespacePath();
524         }
525
526         /* Search syscache by name only */
527         catlist = SearchSysCacheList(PROCNAMEARGSNSP, 1,
528                                                                  CStringGetDatum(funcname),
529                                                                  0, 0, 0);
530
531         for (i = 0; i < catlist->n_members; i++)
532         {
533                 HeapTuple       proctup = &catlist->members[i]->tuple;
534                 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
535                 int                     pronargs = procform->pronargs;
536                 int                     pathpos = 0;
537                 FuncCandidateList newResult;
538
539                 /* Ignore if it doesn't match requested argument count */
540                 if (nargs >= 0 && pronargs != nargs)
541                         continue;
542
543                 if (OidIsValid(namespaceId))
544                 {
545                         /* Consider only procs in specified namespace */
546                         if (procform->pronamespace != namespaceId)
547                                 continue;
548                         /* No need to check args, they must all be different */
549                 }
550                 else
551                 {
552                         /* Consider only procs that are in the search path */
553                         ListCell   *nsp;
554
555                         foreach(nsp, activeSearchPath)
556                         {
557                                 if (procform->pronamespace == lfirst_oid(nsp))
558                                         break;
559                                 pathpos++;
560                         }
561                         if (nsp == NULL)
562                                 continue;               /* proc is not in search path */
563
564                         /*
565                          * Okay, it's in the search path, but does it have the same
566                          * arguments as something we already accepted?  If so, keep only
567                          * the one that appears earlier in the search path.
568                          *
569                          * If we have an ordered list from SearchSysCacheList (the normal
570                          * case), then any conflicting proc must immediately adjoin this
571                          * one in the list, so we only need to look at the newest result
572                          * item.  If we have an unordered list, we have to scan the whole
573                          * result list.
574                          */
575                         if (resultList)
576                         {
577                                 FuncCandidateList prevResult;
578
579                                 if (catlist->ordered)
580                                 {
581                                         if (pronargs == resultList->nargs &&
582                                                 memcmp(procform->proargtypes.values,
583                                                            resultList->args,
584                                                            pronargs * sizeof(Oid)) == 0)
585                                                 prevResult = resultList;
586                                         else
587                                                 prevResult = NULL;
588                                 }
589                                 else
590                                 {
591                                         for (prevResult = resultList;
592                                                  prevResult;
593                                                  prevResult = prevResult->next)
594                                         {
595                                                 if (pronargs == prevResult->nargs &&
596                                                         memcmp(procform->proargtypes.values,
597                                                                    prevResult->args,
598                                                                    pronargs * sizeof(Oid)) == 0)
599                                                         break;
600                                         }
601                                 }
602                                 if (prevResult)
603                                 {
604                                         /* We have a match with a previous result */
605                                         Assert(pathpos != prevResult->pathpos);
606                                         if (pathpos > prevResult->pathpos)
607                                                 continue;               /* keep previous result */
608                                         /* replace previous result */
609                                         prevResult->pathpos = pathpos;
610                                         prevResult->oid = HeapTupleGetOid(proctup);
611                                         continue;       /* args are same, of course */
612                                 }
613                         }
614                 }
615
616                 /*
617                  * Okay to add it to result list
618                  */
619                 newResult = (FuncCandidateList)
620                         palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
621                                    + pronargs * sizeof(Oid));
622                 newResult->pathpos = pathpos;
623                 newResult->oid = HeapTupleGetOid(proctup);
624                 newResult->nargs = pronargs;
625                 memcpy(newResult->args, procform->proargtypes.values,
626                            pronargs * sizeof(Oid));
627
628                 newResult->next = resultList;
629                 resultList = newResult;
630         }
631
632         ReleaseSysCacheList(catlist);
633
634         return resultList;
635 }
636
637 /*
638  * FunctionIsVisible
639  *              Determine whether a function (identified by OID) is visible in the
640  *              current search path.  Visible means "would be found by searching
641  *              for the unqualified function name with exact argument matches".
642  */
643 bool
644 FunctionIsVisible(Oid funcid)
645 {
646         HeapTuple       proctup;
647         Form_pg_proc procform;
648         Oid                     pronamespace;
649         bool            visible;
650
651         proctup = SearchSysCache(PROCOID,
652                                                          ObjectIdGetDatum(funcid),
653                                                          0, 0, 0);
654         if (!HeapTupleIsValid(proctup))
655                 elog(ERROR, "cache lookup failed for function %u", funcid);
656         procform = (Form_pg_proc) GETSTRUCT(proctup);
657
658         recomputeNamespacePath();
659
660         /*
661          * Quick check: if it ain't in the path at all, it ain't visible. Items in
662          * the system namespace are surely in the path and so we needn't even do
663          * list_member_oid() for them.
664          */
665         pronamespace = procform->pronamespace;
666         if (pronamespace != PG_CATALOG_NAMESPACE &&
667                 !list_member_oid(activeSearchPath, pronamespace))
668                 visible = false;
669         else
670         {
671                 /*
672                  * If it is in the path, it might still not be visible; it could be
673                  * hidden by another proc of the same name and arguments earlier in
674                  * the path.  So we must do a slow check to see if this is the same
675                  * proc that would be found by FuncnameGetCandidates.
676                  */
677                 char       *proname = NameStr(procform->proname);
678                 int                     nargs = procform->pronargs;
679                 FuncCandidateList clist;
680
681                 visible = false;
682
683                 clist = FuncnameGetCandidates(list_make1(makeString(proname)), nargs);
684
685                 for (; clist; clist = clist->next)
686                 {
687                         if (memcmp(clist->args, procform->proargtypes.values,
688                                            nargs * sizeof(Oid)) == 0)
689                         {
690                                 /* Found the expected entry; is it the right proc? */
691                                 visible = (clist->oid == funcid);
692                                 break;
693                         }
694                 }
695         }
696
697         ReleaseSysCache(proctup);
698
699         return visible;
700 }
701
702
703 /*
704  * OpernameGetOprid
705  *              Given a possibly-qualified operator name and exact input datatypes,
706  *              look up the operator.  Returns InvalidOid if not found.
707  *
708  * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
709  * a postfix op.
710  *
711  * If the operator name is not schema-qualified, it is sought in the current
712  * namespace search path.
713  */
714 Oid
715 OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
716 {
717         char       *schemaname;
718         char       *opername;
719         CatCList   *catlist;
720         ListCell   *l;
721
722         /* deconstruct the name list */
723         DeconstructQualifiedName(names, &schemaname, &opername);
724
725         if (schemaname)
726         {
727                 /* search only in exact schema given */
728                 Oid                     namespaceId;
729                 HeapTuple       opertup;
730
731                 namespaceId = LookupExplicitNamespace(schemaname);
732                 opertup = SearchSysCache(OPERNAMENSP,
733                                                                  CStringGetDatum(opername),
734                                                                  ObjectIdGetDatum(oprleft),
735                                                                  ObjectIdGetDatum(oprright),
736                                                                  ObjectIdGetDatum(namespaceId));
737                 if (HeapTupleIsValid(opertup))
738                 {
739                         Oid                     result = HeapTupleGetOid(opertup);
740
741                         ReleaseSysCache(opertup);
742                         return result;
743                 }
744                 return InvalidOid;
745         }
746
747         /* Search syscache by name and argument types */
748         catlist = SearchSysCacheList(OPERNAMENSP, 3,
749                                                                  CStringGetDatum(opername),
750                                                                  ObjectIdGetDatum(oprleft),
751                                                                  ObjectIdGetDatum(oprright),
752                                                                  0);
753
754         if (catlist->n_members == 0)
755         {
756                 /* no hope, fall out early */
757                 ReleaseSysCacheList(catlist);
758                 return InvalidOid;
759         }
760
761         /*
762          * We have to find the list member that is first in the search path, if
763          * there's more than one.  This doubly-nested loop looks ugly, but in
764          * practice there should usually be few catlist members.
765          */
766         recomputeNamespacePath();
767
768         foreach(l, activeSearchPath)
769         {
770                 Oid                     namespaceId = lfirst_oid(l);
771                 int                     i;
772
773                 for (i = 0; i < catlist->n_members; i++)
774                 {
775                         HeapTuple       opertup = &catlist->members[i]->tuple;
776                         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
777
778                         if (operform->oprnamespace == namespaceId)
779                         {
780                                 Oid                     result = HeapTupleGetOid(opertup);
781
782                                 ReleaseSysCacheList(catlist);
783                                 return result;
784                         }
785                 }
786         }
787
788         ReleaseSysCacheList(catlist);
789         return InvalidOid;
790 }
791
792 /*
793  * OpernameGetCandidates
794  *              Given a possibly-qualified operator name and operator kind,
795  *              retrieve a list of the possible matches.
796  *
797  * If oprkind is '\0', we return all operators matching the given name,
798  * regardless of arguments.
799  *
800  * We search a single namespace if the operator name is qualified, else
801  * all namespaces in the search path.  The return list will never contain
802  * multiple entries with identical argument lists --- in the multiple-
803  * namespace case, we arrange for entries in earlier namespaces to mask
804  * identical entries in later namespaces.
805  *
806  * The returned items always have two args[] entries --- one or the other
807  * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
808  */
809 FuncCandidateList
810 OpernameGetCandidates(List *names, char oprkind)
811 {
812         FuncCandidateList resultList = NULL;
813         char       *resultSpace = NULL;
814         int                     nextResult = 0;
815         char       *schemaname;
816         char       *opername;
817         Oid                     namespaceId;
818         CatCList   *catlist;
819         int                     i;
820
821         /* deconstruct the name list */
822         DeconstructQualifiedName(names, &schemaname, &opername);
823
824         if (schemaname)
825         {
826                 /* use exact schema given */
827                 namespaceId = LookupExplicitNamespace(schemaname);
828         }
829         else
830         {
831                 /* flag to indicate we need namespace search */
832                 namespaceId = InvalidOid;
833                 recomputeNamespacePath();
834         }
835
836         /* Search syscache by name only */
837         catlist = SearchSysCacheList(OPERNAMENSP, 1,
838                                                                  CStringGetDatum(opername),
839                                                                  0, 0, 0);
840
841         /*
842          * In typical scenarios, most if not all of the operators found by the
843          * catcache search will end up getting returned; and there can be quite a
844          * few, for common operator names such as '=' or '+'.  To reduce the time
845          * spent in palloc, we allocate the result space as an array large enough
846          * to hold all the operators.  The original coding of this routine did a
847          * separate palloc for each operator, but profiling revealed that the
848          * pallocs used an unreasonably large fraction of parsing time.
849          */
850 #define SPACE_PER_OP MAXALIGN(sizeof(struct _FuncCandidateList) + sizeof(Oid))
851
852         if (catlist->n_members > 0)
853                 resultSpace = palloc(catlist->n_members * SPACE_PER_OP);
854
855         for (i = 0; i < catlist->n_members; i++)
856         {
857                 HeapTuple       opertup = &catlist->members[i]->tuple;
858                 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
859                 int                     pathpos = 0;
860                 FuncCandidateList newResult;
861
862                 /* Ignore operators of wrong kind, if specific kind requested */
863                 if (oprkind && operform->oprkind != oprkind)
864                         continue;
865
866                 if (OidIsValid(namespaceId))
867                 {
868                         /* Consider only opers in specified namespace */
869                         if (operform->oprnamespace != namespaceId)
870                                 continue;
871                         /* No need to check args, they must all be different */
872                 }
873                 else
874                 {
875                         /* Consider only opers that are in the search path */
876                         ListCell   *nsp;
877
878                         foreach(nsp, activeSearchPath)
879                         {
880                                 if (operform->oprnamespace == lfirst_oid(nsp))
881                                         break;
882                                 pathpos++;
883                         }
884                         if (nsp == NULL)
885                                 continue;               /* oper is not in search path */
886
887                         /*
888                          * Okay, it's in the search path, but does it have the same
889                          * arguments as something we already accepted?  If so, keep only
890                          * the one that appears earlier in the search path.
891                          *
892                          * If we have an ordered list from SearchSysCacheList (the normal
893                          * case), then any conflicting oper must immediately adjoin this
894                          * one in the list, so we only need to look at the newest result
895                          * item.  If we have an unordered list, we have to scan the whole
896                          * result list.
897                          */
898                         if (resultList)
899                         {
900                                 FuncCandidateList prevResult;
901
902                                 if (catlist->ordered)
903                                 {
904                                         if (operform->oprleft == resultList->args[0] &&
905                                                 operform->oprright == resultList->args[1])
906                                                 prevResult = resultList;
907                                         else
908                                                 prevResult = NULL;
909                                 }
910                                 else
911                                 {
912                                         for (prevResult = resultList;
913                                                  prevResult;
914                                                  prevResult = prevResult->next)
915                                         {
916                                                 if (operform->oprleft == prevResult->args[0] &&
917                                                         operform->oprright == prevResult->args[1])
918                                                         break;
919                                         }
920                                 }
921                                 if (prevResult)
922                                 {
923                                         /* We have a match with a previous result */
924                                         Assert(pathpos != prevResult->pathpos);
925                                         if (pathpos > prevResult->pathpos)
926                                                 continue;               /* keep previous result */
927                                         /* replace previous result */
928                                         prevResult->pathpos = pathpos;
929                                         prevResult->oid = HeapTupleGetOid(opertup);
930                                         continue;       /* args are same, of course */
931                                 }
932                         }
933                 }
934
935                 /*
936                  * Okay to add it to result list
937                  */
938                 newResult = (FuncCandidateList) (resultSpace + nextResult);
939                 nextResult += SPACE_PER_OP;
940
941                 newResult->pathpos = pathpos;
942                 newResult->oid = HeapTupleGetOid(opertup);
943                 newResult->nargs = 2;
944                 newResult->args[0] = operform->oprleft;
945                 newResult->args[1] = operform->oprright;
946                 newResult->next = resultList;
947                 resultList = newResult;
948         }
949
950         ReleaseSysCacheList(catlist);
951
952         return resultList;
953 }
954
955 /*
956  * OperatorIsVisible
957  *              Determine whether an operator (identified by OID) is visible in the
958  *              current search path.  Visible means "would be found by searching
959  *              for the unqualified operator name with exact argument matches".
960  */
961 bool
962 OperatorIsVisible(Oid oprid)
963 {
964         HeapTuple       oprtup;
965         Form_pg_operator oprform;
966         Oid                     oprnamespace;
967         bool            visible;
968
969         oprtup = SearchSysCache(OPEROID,
970                                                         ObjectIdGetDatum(oprid),
971                                                         0, 0, 0);
972         if (!HeapTupleIsValid(oprtup))
973                 elog(ERROR, "cache lookup failed for operator %u", oprid);
974         oprform = (Form_pg_operator) GETSTRUCT(oprtup);
975
976         recomputeNamespacePath();
977
978         /*
979          * Quick check: if it ain't in the path at all, it ain't visible. Items in
980          * the system namespace are surely in the path and so we needn't even do
981          * list_member_oid() for them.
982          */
983         oprnamespace = oprform->oprnamespace;
984         if (oprnamespace != PG_CATALOG_NAMESPACE &&
985                 !list_member_oid(activeSearchPath, oprnamespace))
986                 visible = false;
987         else
988         {
989                 /*
990                  * If it is in the path, it might still not be visible; it could be
991                  * hidden by another operator of the same name and arguments earlier
992                  * in the path.  So we must do a slow check to see if this is the same
993                  * operator that would be found by OpernameGetOprId.
994                  */
995                 char       *oprname = NameStr(oprform->oprname);
996
997                 visible = (OpernameGetOprid(list_make1(makeString(oprname)),
998                                                                         oprform->oprleft, oprform->oprright)
999                                    == oprid);
1000         }
1001
1002         ReleaseSysCache(oprtup);
1003
1004         return visible;
1005 }
1006
1007
1008 /*
1009  * OpclassnameGetOpcid
1010  *              Try to resolve an unqualified index opclass name.
1011  *              Returns OID if opclass found in search path, else InvalidOid.
1012  *
1013  * This is essentially the same as TypenameGetTypid, but we have to have
1014  * an extra argument for the index AM OID.
1015  */
1016 Oid
1017 OpclassnameGetOpcid(Oid amid, const char *opcname)
1018 {
1019         Oid                     opcid;
1020         ListCell   *l;
1021
1022         recomputeNamespacePath();
1023
1024         foreach(l, activeSearchPath)
1025         {
1026                 Oid                     namespaceId = lfirst_oid(l);
1027
1028                 opcid = GetSysCacheOid(CLAAMNAMENSP,
1029                                                            ObjectIdGetDatum(amid),
1030                                                            PointerGetDatum(opcname),
1031                                                            ObjectIdGetDatum(namespaceId),
1032                                                            0);
1033                 if (OidIsValid(opcid))
1034                         return opcid;
1035         }
1036
1037         /* Not found in path */
1038         return InvalidOid;
1039 }
1040
1041 /*
1042  * OpclassIsVisible
1043  *              Determine whether an opclass (identified by OID) is visible in the
1044  *              current search path.  Visible means "would be found by searching
1045  *              for the unqualified opclass name".
1046  */
1047 bool
1048 OpclassIsVisible(Oid opcid)
1049 {
1050         HeapTuple       opctup;
1051         Form_pg_opclass opcform;
1052         Oid                     opcnamespace;
1053         bool            visible;
1054
1055         opctup = SearchSysCache(CLAOID,
1056                                                         ObjectIdGetDatum(opcid),
1057                                                         0, 0, 0);
1058         if (!HeapTupleIsValid(opctup))
1059                 elog(ERROR, "cache lookup failed for opclass %u", opcid);
1060         opcform = (Form_pg_opclass) GETSTRUCT(opctup);
1061
1062         recomputeNamespacePath();
1063
1064         /*
1065          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1066          * the system namespace are surely in the path and so we needn't even do
1067          * list_member_oid() for them.
1068          */
1069         opcnamespace = opcform->opcnamespace;
1070         if (opcnamespace != PG_CATALOG_NAMESPACE &&
1071                 !list_member_oid(activeSearchPath, opcnamespace))
1072                 visible = false;
1073         else
1074         {
1075                 /*
1076                  * If it is in the path, it might still not be visible; it could be
1077                  * hidden by another opclass of the same name earlier in the path. So
1078                  * we must do a slow check to see if this opclass would be found by
1079                  * OpclassnameGetOpcid.
1080                  */
1081                 char       *opcname = NameStr(opcform->opcname);
1082
1083                 visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
1084         }
1085
1086         ReleaseSysCache(opctup);
1087
1088         return visible;
1089 }
1090
1091 /*
1092  * OpfamilynameGetOpfid
1093  *              Try to resolve an unqualified index opfamily name.
1094  *              Returns OID if opfamily found in search path, else InvalidOid.
1095  *
1096  * This is essentially the same as TypenameGetTypid, but we have to have
1097  * an extra argument for the index AM OID.
1098  */
1099 Oid
1100 OpfamilynameGetOpfid(Oid amid, const char *opfname)
1101 {
1102         Oid                     opfid;
1103         ListCell   *l;
1104
1105         recomputeNamespacePath();
1106
1107         foreach(l, activeSearchPath)
1108         {
1109                 Oid                     namespaceId = lfirst_oid(l);
1110
1111                 opfid = GetSysCacheOid(OPFAMILYAMNAMENSP,
1112                                                            ObjectIdGetDatum(amid),
1113                                                            PointerGetDatum(opfname),
1114                                                            ObjectIdGetDatum(namespaceId),
1115                                                            0);
1116                 if (OidIsValid(opfid))
1117                         return opfid;
1118         }
1119
1120         /* Not found in path */
1121         return InvalidOid;
1122 }
1123
1124 /*
1125  * OpfamilyIsVisible
1126  *              Determine whether an opfamily (identified by OID) is visible in the
1127  *              current search path.  Visible means "would be found by searching
1128  *              for the unqualified opfamily name".
1129  */
1130 bool
1131 OpfamilyIsVisible(Oid opfid)
1132 {
1133         HeapTuple       opftup;
1134         Form_pg_opfamily opfform;
1135         Oid                     opfnamespace;
1136         bool            visible;
1137
1138         opftup = SearchSysCache(OPFAMILYOID,
1139                                                         ObjectIdGetDatum(opfid),
1140                                                         0, 0, 0);
1141         if (!HeapTupleIsValid(opftup))
1142                 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
1143         opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
1144
1145         recomputeNamespacePath();
1146
1147         /*
1148          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1149          * the system namespace are surely in the path and so we needn't even do
1150          * list_member_oid() for them.
1151          */
1152         opfnamespace = opfform->opfnamespace;
1153         if (opfnamespace != PG_CATALOG_NAMESPACE &&
1154                 !list_member_oid(activeSearchPath, opfnamespace))
1155                 visible = false;
1156         else
1157         {
1158                 /*
1159                  * If it is in the path, it might still not be visible; it could be
1160                  * hidden by another opfamily of the same name earlier in the path. So
1161                  * we must do a slow check to see if this opfamily would be found by
1162                  * OpfamilynameGetOpfid.
1163                  */
1164                 char       *opfname = NameStr(opfform->opfname);
1165
1166                 visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
1167         }
1168
1169         ReleaseSysCache(opftup);
1170
1171         return visible;
1172 }
1173
1174 /*
1175  * ConversionGetConid
1176  *              Try to resolve an unqualified conversion name.
1177  *              Returns OID if conversion found in search path, else InvalidOid.
1178  *
1179  * This is essentially the same as RelnameGetRelid.
1180  */
1181 Oid
1182 ConversionGetConid(const char *conname)
1183 {
1184         Oid                     conid;
1185         ListCell   *l;
1186
1187         recomputeNamespacePath();
1188
1189         foreach(l, activeSearchPath)
1190         {
1191                 Oid                     namespaceId = lfirst_oid(l);
1192
1193                 conid = GetSysCacheOid(CONNAMENSP,
1194                                                            PointerGetDatum(conname),
1195                                                            ObjectIdGetDatum(namespaceId),
1196                                                            0, 0);
1197                 if (OidIsValid(conid))
1198                         return conid;
1199         }
1200
1201         /* Not found in path */
1202         return InvalidOid;
1203 }
1204
1205 /*
1206  * ConversionIsVisible
1207  *              Determine whether a conversion (identified by OID) is visible in the
1208  *              current search path.  Visible means "would be found by searching
1209  *              for the unqualified conversion name".
1210  */
1211 bool
1212 ConversionIsVisible(Oid conid)
1213 {
1214         HeapTuple       contup;
1215         Form_pg_conversion conform;
1216         Oid                     connamespace;
1217         bool            visible;
1218
1219         contup = SearchSysCache(CONVOID,
1220                                                         ObjectIdGetDatum(conid),
1221                                                         0, 0, 0);
1222         if (!HeapTupleIsValid(contup))
1223                 elog(ERROR, "cache lookup failed for conversion %u", conid);
1224         conform = (Form_pg_conversion) GETSTRUCT(contup);
1225
1226         recomputeNamespacePath();
1227
1228         /*
1229          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1230          * the system namespace are surely in the path and so we needn't even do
1231          * list_member_oid() for them.
1232          */
1233         connamespace = conform->connamespace;
1234         if (connamespace != PG_CATALOG_NAMESPACE &&
1235                 !list_member_oid(activeSearchPath, connamespace))
1236                 visible = false;
1237         else
1238         {
1239                 /*
1240                  * If it is in the path, it might still not be visible; it could be
1241                  * hidden by another conversion of the same name earlier in the path.
1242                  * So we must do a slow check to see if this conversion would be found
1243                  * by ConversionGetConid.
1244                  */
1245                 char       *conname = NameStr(conform->conname);
1246
1247                 visible = (ConversionGetConid(conname) == conid);
1248         }
1249
1250         ReleaseSysCache(contup);
1251
1252         return visible;
1253 }
1254
1255 /*
1256  * DeconstructQualifiedName
1257  *              Given a possibly-qualified name expressed as a list of String nodes,
1258  *              extract the schema name and object name.
1259  *
1260  * *nspname_p is set to NULL if there is no explicit schema name.
1261  */
1262 void
1263 DeconstructQualifiedName(List *names,
1264                                                  char **nspname_p,
1265                                                  char **objname_p)
1266 {
1267         char       *catalogname;
1268         char       *schemaname = NULL;
1269         char       *objname = NULL;
1270
1271         switch (list_length(names))
1272         {
1273                 case 1:
1274                         objname = strVal(linitial(names));
1275                         break;
1276                 case 2:
1277                         schemaname = strVal(linitial(names));
1278                         objname = strVal(lsecond(names));
1279                         break;
1280                 case 3:
1281                         catalogname = strVal(linitial(names));
1282                         schemaname = strVal(lsecond(names));
1283                         objname = strVal(lthird(names));
1284
1285                         /*
1286                          * We check the catalog name and then ignore it.
1287                          */
1288                         if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
1289                                 ereport(ERROR,
1290                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1291                                   errmsg("cross-database references are not implemented: %s",
1292                                                  NameListToString(names))));
1293                         break;
1294                 default:
1295                         ereport(ERROR,
1296                                         (errcode(ERRCODE_SYNTAX_ERROR),
1297                                 errmsg("improper qualified name (too many dotted names): %s",
1298                                            NameListToString(names))));
1299                         break;
1300         }
1301
1302         *nspname_p = schemaname;
1303         *objname_p = objname;
1304 }
1305
1306 /*
1307  * LookupExplicitNamespace
1308  *              Process an explicitly-specified schema name: look up the schema
1309  *              and verify we have USAGE (lookup) rights in it.
1310  *
1311  * Returns the namespace OID.  Raises ereport if any problem.
1312  */
1313 Oid
1314 LookupExplicitNamespace(const char *nspname)
1315 {
1316         Oid                     namespaceId;
1317         AclResult       aclresult;
1318
1319         namespaceId = GetSysCacheOid(NAMESPACENAME,
1320                                                                  CStringGetDatum(nspname),
1321                                                                  0, 0, 0);
1322         if (!OidIsValid(namespaceId))
1323                 ereport(ERROR,
1324                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1325                                  errmsg("schema \"%s\" does not exist", nspname)));
1326
1327         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
1328         if (aclresult != ACLCHECK_OK)
1329                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1330                                            nspname);
1331
1332         return namespaceId;
1333 }
1334
1335 /*
1336  * LookupCreationNamespace
1337  *              Look up the schema and verify we have CREATE rights on it.
1338  *
1339  * This is just like LookupExplicitNamespace except for the permission check.
1340  */
1341 Oid
1342 LookupCreationNamespace(const char *nspname)
1343 {
1344         Oid                     namespaceId;
1345         AclResult       aclresult;
1346
1347         namespaceId = GetSysCacheOid(NAMESPACENAME,
1348                                                                  CStringGetDatum(nspname),
1349                                                                  0, 0, 0);
1350         if (!OidIsValid(namespaceId))
1351                 ereport(ERROR,
1352                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1353                                  errmsg("schema \"%s\" does not exist", nspname)));
1354
1355         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
1356         if (aclresult != ACLCHECK_OK)
1357                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1358                                            nspname);
1359
1360         return namespaceId;
1361 }
1362
1363 /*
1364  * QualifiedNameGetCreationNamespace
1365  *              Given a possibly-qualified name for an object (in List-of-Values
1366  *              format), determine what namespace the object should be created in.
1367  *              Also extract and return the object name (last component of list).
1368  *
1369  * Note: this does not apply any permissions check.  Callers must check
1370  * for CREATE rights on the selected namespace when appropriate.
1371  *
1372  * This is *not* used for tables.  Hence, the TEMP table namespace is
1373  * never selected as the creation target.
1374  */
1375 Oid
1376 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
1377 {
1378         char       *schemaname;
1379         char       *objname;
1380         Oid                     namespaceId;
1381
1382         /* deconstruct the name list */
1383         DeconstructQualifiedName(names, &schemaname, &objname);
1384
1385         if (schemaname)
1386         {
1387                 /* use exact schema given */
1388                 namespaceId = GetSysCacheOid(NAMESPACENAME,
1389                                                                          CStringGetDatum(schemaname),
1390                                                                          0, 0, 0);
1391                 if (!OidIsValid(namespaceId))
1392                         ereport(ERROR,
1393                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
1394                                          errmsg("schema \"%s\" does not exist", schemaname)));
1395                 /* we do not check for USAGE rights here! */
1396         }
1397         else
1398         {
1399                 /* use the default creation namespace */
1400                 recomputeNamespacePath();
1401                 namespaceId = activeCreationNamespace;
1402                 if (!OidIsValid(namespaceId))
1403                         ereport(ERROR,
1404                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
1405                                          errmsg("no schema has been selected to create in")));
1406         }
1407
1408         *objname_p = objname;
1409         return namespaceId;
1410 }
1411
1412 /*
1413  * makeRangeVarFromNameList
1414  *              Utility routine to convert a qualified-name list into RangeVar form.
1415  */
1416 RangeVar *
1417 makeRangeVarFromNameList(List *names)
1418 {
1419         RangeVar   *rel = makeRangeVar(NULL, NULL);
1420
1421         switch (list_length(names))
1422         {
1423                 case 1:
1424                         rel->relname = strVal(linitial(names));
1425                         break;
1426                 case 2:
1427                         rel->schemaname = strVal(linitial(names));
1428                         rel->relname = strVal(lsecond(names));
1429                         break;
1430                 case 3:
1431                         rel->catalogname = strVal(linitial(names));
1432                         rel->schemaname = strVal(lsecond(names));
1433                         rel->relname = strVal(lthird(names));
1434                         break;
1435                 default:
1436                         ereport(ERROR,
1437                                         (errcode(ERRCODE_SYNTAX_ERROR),
1438                                  errmsg("improper relation name (too many dotted names): %s",
1439                                                 NameListToString(names))));
1440                         break;
1441         }
1442
1443         return rel;
1444 }
1445
1446 /*
1447  * NameListToString
1448  *              Utility routine to convert a qualified-name list into a string.
1449  *
1450  * This is used primarily to form error messages, and so we do not quote
1451  * the list elements, for the sake of legibility.
1452  */
1453 char *
1454 NameListToString(List *names)
1455 {
1456         StringInfoData string;
1457         ListCell   *l;
1458
1459         initStringInfo(&string);
1460
1461         foreach(l, names)
1462         {
1463                 if (l != list_head(names))
1464                         appendStringInfoChar(&string, '.');
1465                 appendStringInfoString(&string, strVal(lfirst(l)));
1466         }
1467
1468         return string.data;
1469 }
1470
1471 /*
1472  * NameListToQuotedString
1473  *              Utility routine to convert a qualified-name list into a string.
1474  *
1475  * Same as above except that names will be double-quoted where necessary,
1476  * so the string could be re-parsed (eg, by textToQualifiedNameList).
1477  */
1478 char *
1479 NameListToQuotedString(List *names)
1480 {
1481         StringInfoData string;
1482         ListCell   *l;
1483
1484         initStringInfo(&string);
1485
1486         foreach(l, names)
1487         {
1488                 if (l != list_head(names))
1489                         appendStringInfoChar(&string, '.');
1490                 appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
1491         }
1492
1493         return string.data;
1494 }
1495
1496 /*
1497  * isTempNamespace - is the given namespace my temporary-table namespace?
1498  */
1499 bool
1500 isTempNamespace(Oid namespaceId)
1501 {
1502         if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
1503                 return true;
1504         return false;
1505 }
1506
1507 /*
1508  * isAnyTempNamespace - is the given namespace a temporary-table namespace
1509  * (either my own, or another backend's)?
1510  */
1511 bool
1512 isAnyTempNamespace(Oid namespaceId)
1513 {
1514         bool            result;
1515         char       *nspname;
1516
1517         /* If the namespace name starts with "pg_temp_", say "true" */
1518         nspname = get_namespace_name(namespaceId);
1519         if (!nspname)
1520                 return false;                   /* no such namespace? */
1521         result = (strncmp(nspname, "pg_temp_", 8) == 0);
1522         pfree(nspname);
1523         return result;
1524 }
1525
1526 /*
1527  * isOtherTempNamespace - is the given namespace some other backend's
1528  * temporary-table namespace?
1529  */
1530 bool
1531 isOtherTempNamespace(Oid namespaceId)
1532 {
1533         /* If it's my own temp namespace, say "false" */
1534         if (isTempNamespace(namespaceId))
1535                 return false;
1536         /* Else, if the namespace name starts with "pg_temp_", say "true" */
1537         return isAnyTempNamespace(namespaceId);
1538 }
1539
1540
1541 /*
1542  * GetOverrideSearchPath - fetch current search path definition in form
1543  * used by PushOverrideSearchPath.
1544  *
1545  * The result structure is allocated in the specified memory context
1546  * (which might or might not be equal to CurrentMemoryContext); but any
1547  * junk created by revalidation calculations will be in CurrentMemoryContext.
1548  */
1549 OverrideSearchPath *
1550 GetOverrideSearchPath(MemoryContext context)
1551 {
1552         OverrideSearchPath *result;
1553         List       *schemas;
1554         MemoryContext oldcxt;
1555
1556         recomputeNamespacePath();
1557
1558         oldcxt = MemoryContextSwitchTo(context);
1559
1560         result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
1561         schemas = list_copy(activeSearchPath);
1562         while (schemas && linitial_oid(schemas) != activeCreationNamespace)
1563         {
1564                 if (linitial_oid(schemas) == myTempNamespace)
1565                         result->addTemp = true;
1566                 else
1567                 {
1568                         Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
1569                         result->addCatalog = true;
1570                 }
1571                 schemas = list_delete_first(schemas);
1572         }
1573         result->schemas = schemas;
1574
1575         MemoryContextSwitchTo(oldcxt);
1576
1577         return result;
1578 }
1579
1580 /*
1581  * PushOverrideSearchPath - temporarily override the search path
1582  *
1583  * We allow nested overrides, hence the push/pop terminology.  The GUC
1584  * search_path variable is ignored while an override is active.
1585  */
1586 void
1587 PushOverrideSearchPath(OverrideSearchPath *newpath)
1588 {
1589         OverrideStackEntry *entry;
1590         List       *oidlist;
1591         Oid                     firstNS;
1592         MemoryContext oldcxt;
1593
1594         /*
1595          * Copy the list for safekeeping, and insert implicitly-searched
1596          * namespaces as needed.  This code should track recomputeNamespacePath.
1597          */
1598         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1599
1600         oidlist = list_copy(newpath->schemas);
1601
1602         /*
1603          * Remember the first member of the explicit list.
1604          */
1605         if (oidlist == NIL)
1606                 firstNS = InvalidOid;
1607         else
1608                 firstNS = linitial_oid(oidlist);
1609
1610         /*
1611          * Add any implicitly-searched namespaces to the list.  Note these go on
1612          * the front, not the back; also notice that we do not check USAGE
1613          * permissions for these.
1614          */
1615         if (newpath->addCatalog)
1616                 oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
1617
1618         if (newpath->addTemp)
1619         {
1620                 Assert(OidIsValid(myTempNamespace));
1621                 oidlist = lcons_oid(myTempNamespace, oidlist);
1622         }
1623
1624         /*
1625          * Build the new stack entry, then insert it at the head of the list.
1626          */
1627         entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
1628         entry->searchPath = oidlist;
1629         entry->creationNamespace = firstNS;
1630         entry->nestLevel = GetCurrentTransactionNestLevel();
1631
1632         overrideStack = lcons(entry, overrideStack);
1633
1634         /* And make it active. */
1635         activeSearchPath = entry->searchPath;
1636         activeCreationNamespace = entry->creationNamespace;
1637
1638         MemoryContextSwitchTo(oldcxt);
1639 }
1640
1641 /*
1642  * PopOverrideSearchPath - undo a previous PushOverrideSearchPath
1643  *
1644  * Any push during a (sub)transaction will be popped automatically at abort.
1645  * But it's caller error if a push isn't popped in normal control flow.
1646  */
1647 void
1648 PopOverrideSearchPath(void)
1649 {
1650         OverrideStackEntry *entry;
1651
1652         /* Sanity checks. */
1653         if (overrideStack == NIL)
1654                 elog(ERROR, "bogus PopOverrideSearchPath call");
1655         entry = (OverrideStackEntry *) linitial(overrideStack);
1656         if (entry->nestLevel != GetCurrentTransactionNestLevel())
1657                 elog(ERROR, "bogus PopOverrideSearchPath call");
1658
1659         /* Pop the stack and free storage. */
1660         overrideStack = list_delete_first(overrideStack);
1661         list_free(entry->searchPath);
1662         pfree(entry);
1663
1664         /* Activate the next level down. */
1665         if (overrideStack)
1666         {
1667                 entry = (OverrideStackEntry *) linitial(overrideStack);
1668                 activeSearchPath = entry->searchPath;
1669                 activeCreationNamespace = entry->creationNamespace;
1670         }
1671         else
1672         {
1673                 /* If not baseSearchPathValid, this is useless but harmless */
1674                 activeSearchPath = baseSearchPath;
1675                 activeCreationNamespace = baseCreationNamespace;
1676         }
1677 }
1678
1679
1680 /*
1681  * FindConversionByName - find a conversion by possibly qualified name
1682  */
1683 Oid
1684 FindConversionByName(List *name)
1685 {
1686         char       *schemaname;
1687         char       *conversion_name;
1688         Oid                     namespaceId;
1689         Oid                     conoid;
1690         ListCell   *l;
1691
1692         /* deconstruct the name list */
1693         DeconstructQualifiedName(name, &schemaname, &conversion_name);
1694
1695         if (schemaname)
1696         {
1697                 /* use exact schema given */
1698                 namespaceId = LookupExplicitNamespace(schemaname);
1699                 return FindConversion(conversion_name, namespaceId);
1700         }
1701         else
1702         {
1703                 /* search for it in search path */
1704                 recomputeNamespacePath();
1705
1706                 foreach(l, activeSearchPath)
1707                 {
1708                         namespaceId = lfirst_oid(l);
1709                         conoid = FindConversion(conversion_name, namespaceId);
1710                         if (OidIsValid(conoid))
1711                                 return conoid;
1712                 }
1713         }
1714
1715         /* Not found in path */
1716         return InvalidOid;
1717 }
1718
1719 /*
1720  * FindDefaultConversionProc - find default encoding conversion proc
1721  */
1722 Oid
1723 FindDefaultConversionProc(int4 for_encoding, int4 to_encoding)
1724 {
1725         Oid                     proc;
1726         ListCell   *l;
1727
1728         recomputeNamespacePath();
1729
1730         foreach(l, activeSearchPath)
1731         {
1732                 Oid                     namespaceId = lfirst_oid(l);
1733
1734                 proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
1735                 if (OidIsValid(proc))
1736                         return proc;
1737         }
1738
1739         /* Not found in path */
1740         return InvalidOid;
1741 }
1742
1743 /*
1744  * recomputeNamespacePath - recompute path derived variables if needed.
1745  */
1746 static void
1747 recomputeNamespacePath(void)
1748 {
1749         Oid                     roleid = GetUserId();
1750         char       *rawname;
1751         List       *namelist;
1752         List       *oidlist;
1753         List       *newpath;
1754         ListCell   *l;
1755         Oid                     firstNS;
1756         MemoryContext oldcxt;
1757
1758         /* Do nothing if an override search spec is active. */
1759         if (overrideStack)
1760                 return;
1761
1762         /* Do nothing if path is already valid. */
1763         if (baseSearchPathValid && namespaceUser == roleid)
1764                 return;
1765
1766         /* Need a modifiable copy of namespace_search_path string */
1767         rawname = pstrdup(namespace_search_path);
1768
1769         /* Parse string into list of identifiers */
1770         if (!SplitIdentifierString(rawname, ',', &namelist))
1771         {
1772                 /* syntax error in name list */
1773                 /* this should not happen if GUC checked check_search_path */
1774                 elog(ERROR, "invalid list syntax");
1775         }
1776
1777         /*
1778          * Convert the list of names to a list of OIDs.  If any names are not
1779          * recognizable or we don't have read access, just leave them out of the
1780          * list.  (We can't raise an error, since the search_path setting has
1781          * already been accepted.)      Don't make duplicate entries, either.
1782          */
1783         oidlist = NIL;
1784         foreach(l, namelist)
1785         {
1786                 char       *curname = (char *) lfirst(l);
1787                 Oid                     namespaceId;
1788
1789                 if (strcmp(curname, "$user") == 0)
1790                 {
1791                         /* $user --- substitute namespace matching user name, if any */
1792                         HeapTuple       tuple;
1793
1794                         tuple = SearchSysCache(AUTHOID,
1795                                                                    ObjectIdGetDatum(roleid),
1796                                                                    0, 0, 0);
1797                         if (HeapTupleIsValid(tuple))
1798                         {
1799                                 char       *rname;
1800
1801                                 rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
1802                                 namespaceId = GetSysCacheOid(NAMESPACENAME,
1803                                                                                          CStringGetDatum(rname),
1804                                                                                          0, 0, 0);
1805                                 ReleaseSysCache(tuple);
1806                                 if (OidIsValid(namespaceId) &&
1807                                         !list_member_oid(oidlist, namespaceId) &&
1808                                         pg_namespace_aclcheck(namespaceId, roleid,
1809                                                                                   ACL_USAGE) == ACLCHECK_OK)
1810                                         oidlist = lappend_oid(oidlist, namespaceId);
1811                         }
1812                 }
1813                 else
1814                 {
1815                         /* normal namespace reference */
1816                         namespaceId = GetSysCacheOid(NAMESPACENAME,
1817                                                                                  CStringGetDatum(curname),
1818                                                                                  0, 0, 0);
1819                         if (OidIsValid(namespaceId) &&
1820                                 !list_member_oid(oidlist, namespaceId) &&
1821                                 pg_namespace_aclcheck(namespaceId, roleid,
1822                                                                           ACL_USAGE) == ACLCHECK_OK)
1823                                 oidlist = lappend_oid(oidlist, namespaceId);
1824                 }
1825         }
1826
1827         /*
1828          * Remember the first member of the explicit list.
1829          */
1830         if (oidlist == NIL)
1831                 firstNS = InvalidOid;
1832         else
1833                 firstNS = linitial_oid(oidlist);
1834
1835         /*
1836          * Add any implicitly-searched namespaces to the list.  Note these go on
1837          * the front, not the back; also notice that we do not check USAGE
1838          * permissions for these.
1839          */
1840         if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
1841                 oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
1842
1843         if (OidIsValid(myTempNamespace) &&
1844                 !list_member_oid(oidlist, myTempNamespace))
1845                 oidlist = lcons_oid(myTempNamespace, oidlist);
1846
1847         /*
1848          * Now that we've successfully built the new list of namespace OIDs, save
1849          * it in permanent storage.
1850          */
1851         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1852         newpath = list_copy(oidlist);
1853         MemoryContextSwitchTo(oldcxt);
1854
1855         /* Now safe to assign to state variables. */
1856         list_free(baseSearchPath);
1857         baseSearchPath = newpath;
1858         baseCreationNamespace = firstNS;
1859
1860         /* Mark the path valid. */
1861         baseSearchPathValid = true;
1862         namespaceUser = roleid;
1863
1864         /* And make it active. */
1865         activeSearchPath = baseSearchPath;
1866         activeCreationNamespace = baseCreationNamespace;
1867
1868         /* Clean up. */
1869         pfree(rawname);
1870         list_free(namelist);
1871         list_free(oidlist);
1872 }
1873
1874 /*
1875  * InitTempTableNamespace
1876  *              Initialize temp table namespace on first use in a particular backend
1877  */
1878 static void
1879 InitTempTableNamespace(void)
1880 {
1881         char            namespaceName[NAMEDATALEN];
1882         Oid                     namespaceId;
1883
1884         /*
1885          * First, do permission check to see if we are authorized to make temp
1886          * tables.      We use a nonstandard error message here since "databasename:
1887          * permission denied" might be a tad cryptic.
1888          *
1889          * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
1890          * that's necessary since current user ID could change during the session.
1891          * But there's no need to make the namespace in the first place until a
1892          * temp table creation request is made by someone with appropriate rights.
1893          */
1894         if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
1895                                                          ACL_CREATE_TEMP) != ACLCHECK_OK)
1896                 ereport(ERROR,
1897                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1898                                  errmsg("permission denied to create temporary tables in database \"%s\"",
1899                                                 get_database_name(MyDatabaseId))));
1900
1901         snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
1902
1903         namespaceId = GetSysCacheOid(NAMESPACENAME,
1904                                                                  CStringGetDatum(namespaceName),
1905                                                                  0, 0, 0);
1906         if (!OidIsValid(namespaceId))
1907         {
1908                 /*
1909                  * First use of this temp namespace in this database; create it. The
1910                  * temp namespaces are always owned by the superuser.  We leave their
1911                  * permissions at default --- i.e., no access except to superuser ---
1912                  * to ensure that unprivileged users can't peek at other backends'
1913                  * temp tables.  This works because the places that access the temp
1914                  * namespace for my own backend skip permissions checks on it.
1915                  */
1916                 namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
1917                 /* Advance command counter to make namespace visible */
1918                 CommandCounterIncrement();
1919         }
1920         else
1921         {
1922                 /*
1923                  * If the namespace already exists, clean it out (in case the former
1924                  * owner crashed without doing so).
1925                  */
1926                 RemoveTempRelations(namespaceId);
1927         }
1928
1929         /*
1930          * Okay, we've prepared the temp namespace ... but it's not committed yet,
1931          * so all our work could be undone by transaction rollback.  Set flag for
1932          * AtEOXact_Namespace to know what to do.
1933          */
1934         myTempNamespace = namespaceId;
1935
1936         /* It should not be done already. */
1937         AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
1938         myTempNamespaceSubID = GetCurrentSubTransactionId();
1939
1940         baseSearchPathValid = false;    /* need to rebuild list */
1941 }
1942
1943 /*
1944  * End-of-transaction cleanup for namespaces.
1945  */
1946 void
1947 AtEOXact_Namespace(bool isCommit)
1948 {
1949         /*
1950          * If we abort the transaction in which a temp namespace was selected,
1951          * we'll have to do any creation or cleanout work over again.  So, just
1952          * forget the namespace entirely until next time.  On the other hand, if
1953          * we commit then register an exit callback to clean out the temp tables
1954          * at backend shutdown.  (We only want to register the callback once per
1955          * session, so this is a good place to do it.)
1956          */
1957         if (myTempNamespaceSubID != InvalidSubTransactionId)
1958         {
1959                 if (isCommit)
1960                         on_shmem_exit(RemoveTempRelationsCallback, 0);
1961                 else
1962                 {
1963                         myTempNamespace = InvalidOid;
1964                         baseSearchPathValid = false;    /* need to rebuild list */
1965                 }
1966                 myTempNamespaceSubID = InvalidSubTransactionId;
1967         }
1968
1969         /*
1970          * Clean up if someone failed to do PopOverrideSearchPath
1971          */
1972         if (overrideStack)
1973         {
1974                 if (isCommit)
1975                         elog(WARNING, "leaked override search path");
1976                 while (overrideStack)
1977                 {
1978                         OverrideStackEntry *entry;
1979
1980                         entry = (OverrideStackEntry *) linitial(overrideStack);
1981                         overrideStack = list_delete_first(overrideStack);
1982                         list_free(entry->searchPath);
1983                         pfree(entry);
1984                 }
1985                 /* If not baseSearchPathValid, this is useless but harmless */
1986                 activeSearchPath = baseSearchPath;
1987                 activeCreationNamespace = baseCreationNamespace;
1988         }
1989 }
1990
1991 /*
1992  * AtEOSubXact_Namespace
1993  *
1994  * At subtransaction commit, propagate the temp-namespace-creation
1995  * flag to the parent subtransaction.
1996  *
1997  * At subtransaction abort, forget the flag if we set it up.
1998  */
1999 void
2000 AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
2001                                           SubTransactionId parentSubid)
2002 {
2003         OverrideStackEntry *entry;
2004
2005         if (myTempNamespaceSubID == mySubid)
2006         {
2007                 if (isCommit)
2008                         myTempNamespaceSubID = parentSubid;
2009                 else
2010                 {
2011                         myTempNamespaceSubID = InvalidSubTransactionId;
2012                         /* TEMP namespace creation failed, so reset state */
2013                         myTempNamespace = InvalidOid;
2014                         baseSearchPathValid = false;    /* need to rebuild list */
2015                 }
2016         }
2017
2018         /*
2019          * Clean up if someone failed to do PopOverrideSearchPath
2020          */
2021         while (overrideStack)
2022         {
2023                 entry = (OverrideStackEntry *) linitial(overrideStack);
2024                 if (entry->nestLevel < GetCurrentTransactionNestLevel())
2025                         break;
2026                 if (isCommit)
2027                         elog(WARNING, "leaked override search path");
2028                 overrideStack = list_delete_first(overrideStack);
2029                 list_free(entry->searchPath);
2030                 pfree(entry);
2031         }
2032
2033         /* Activate the next level down. */
2034         if (overrideStack)
2035         {
2036                 entry = (OverrideStackEntry *) linitial(overrideStack);
2037                 activeSearchPath = entry->searchPath;
2038                 activeCreationNamespace = entry->creationNamespace;
2039         }
2040         else
2041         {
2042                 /* If not baseSearchPathValid, this is useless but harmless */
2043                 activeSearchPath = baseSearchPath;
2044                 activeCreationNamespace = baseCreationNamespace;
2045         }
2046 }
2047
2048 /*
2049  * Remove all relations in the specified temp namespace.
2050  *
2051  * This is called at backend shutdown (if we made any temp relations).
2052  * It is also called when we begin using a pre-existing temp namespace,
2053  * in order to clean out any relations that might have been created by
2054  * a crashed backend.
2055  */
2056 static void
2057 RemoveTempRelations(Oid tempNamespaceId)
2058 {
2059         ObjectAddress object;
2060
2061         /*
2062          * We want to get rid of everything in the target namespace, but not the
2063          * namespace itself (deleting it only to recreate it later would be a
2064          * waste of cycles).  We do this by finding everything that has a
2065          * dependency on the namespace.
2066          */
2067         object.classId = NamespaceRelationId;
2068         object.objectId = tempNamespaceId;
2069         object.objectSubId = 0;
2070
2071         deleteWhatDependsOn(&object, false);
2072 }
2073
2074 /*
2075  * Callback to remove temp relations at backend exit.
2076  */
2077 static void
2078 RemoveTempRelationsCallback(int code, Datum arg)
2079 {
2080         if (OidIsValid(myTempNamespace))        /* should always be true */
2081         {
2082                 /* Need to ensure we have a usable transaction. */
2083                 AbortOutOfAnyTransaction();
2084                 StartTransactionCommand();
2085
2086                 RemoveTempRelations(myTempNamespace);
2087
2088                 CommitTransactionCommand();
2089         }
2090 }
2091
2092
2093 /*
2094  * Routines for handling the GUC variable 'search_path'.
2095  */
2096
2097 /* assign_hook: validate new search_path, do extra actions as needed */
2098 const char *
2099 assign_search_path(const char *newval, bool doit, GucSource source)
2100 {
2101         char       *rawname;
2102         List       *namelist;
2103         ListCell   *l;
2104
2105         /* Need a modifiable copy of string */
2106         rawname = pstrdup(newval);
2107
2108         /* Parse string into list of identifiers */
2109         if (!SplitIdentifierString(rawname, ',', &namelist))
2110         {
2111                 /* syntax error in name list */
2112                 pfree(rawname);
2113                 list_free(namelist);
2114                 return NULL;
2115         }
2116
2117         /*
2118          * If we aren't inside a transaction, we cannot do database access so
2119          * cannot verify the individual names.  Must accept the list on faith.
2120          */
2121         if (source >= PGC_S_INTERACTIVE && IsTransactionState())
2122         {
2123                 /*
2124                  * Verify that all the names are either valid namespace names or
2125                  * "$user".  We do not require $user to correspond to a valid
2126                  * namespace.  We do not check for USAGE rights, either; should we?
2127                  *
2128                  * When source == PGC_S_TEST, we are checking the argument of an ALTER
2129                  * DATABASE SET or ALTER USER SET command.      It could be that the
2130                  * intended use of the search path is for some other database, so we
2131                  * should not error out if it mentions schemas not present in the
2132                  * current database.  We reduce the message to NOTICE instead.
2133                  */
2134                 foreach(l, namelist)
2135                 {
2136                         char       *curname = (char *) lfirst(l);
2137
2138                         if (strcmp(curname, "$user") == 0)
2139                                 continue;
2140                         if (!SearchSysCacheExists(NAMESPACENAME,
2141                                                                           CStringGetDatum(curname),
2142                                                                           0, 0, 0))
2143                                 ereport((source == PGC_S_TEST) ? NOTICE : ERROR,
2144                                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2145                                                  errmsg("schema \"%s\" does not exist", curname)));
2146                 }
2147         }
2148
2149         pfree(rawname);
2150         list_free(namelist);
2151
2152         /*
2153          * We mark the path as needing recomputation, but don't do anything until
2154          * it's needed.  This avoids trying to do database access during GUC
2155          * initialization.
2156          */
2157         if (doit)
2158                 baseSearchPathValid = false;
2159
2160         return newval;
2161 }
2162
2163 /*
2164  * InitializeSearchPath: initialize module during InitPostgres.
2165  *
2166  * This is called after we are up enough to be able to do catalog lookups.
2167  */
2168 void
2169 InitializeSearchPath(void)
2170 {
2171         if (IsBootstrapProcessingMode())
2172         {
2173                 /*
2174                  * In bootstrap mode, the search path must be 'pg_catalog' so that
2175                  * tables are created in the proper namespace; ignore the GUC setting.
2176                  */
2177                 MemoryContext oldcxt;
2178
2179                 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
2180                 baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
2181                 MemoryContextSwitchTo(oldcxt);
2182                 baseCreationNamespace = PG_CATALOG_NAMESPACE;
2183                 baseSearchPathValid = true;
2184                 namespaceUser = GetUserId();
2185                 activeSearchPath = baseSearchPath;
2186                 activeCreationNamespace = baseCreationNamespace;
2187         }
2188         else
2189         {
2190                 /*
2191                  * In normal mode, arrange for a callback on any syscache invalidation
2192                  * of pg_namespace rows.
2193                  */
2194                 CacheRegisterSyscacheCallback(NAMESPACEOID,
2195                                                                           NamespaceCallback,
2196                                                                           (Datum) 0);
2197                 /* Force search path to be recomputed on next use */
2198                 baseSearchPathValid = false;
2199         }
2200 }
2201
2202 /*
2203  * NamespaceCallback
2204  *              Syscache inval callback function
2205  */
2206 static void
2207 NamespaceCallback(Datum arg, Oid relid)
2208 {
2209         /* Force search path to be recomputed on next use */
2210         baseSearchPathValid = false;
2211 }
2212
2213 /*
2214  * Fetch the active search path. The return value is a palloc'ed list
2215  * of OIDs; the caller is responsible for freeing this storage as
2216  * appropriate.
2217  *
2218  * The returned list includes the implicitly-prepended namespaces only if
2219  * includeImplicit is true.
2220  */
2221 List *
2222 fetch_search_path(bool includeImplicit)
2223 {
2224         List       *result;
2225
2226         recomputeNamespacePath();
2227
2228         result = list_copy(activeSearchPath);
2229         if (!includeImplicit)
2230         {
2231                 while (result && linitial_oid(result) != activeCreationNamespace)
2232                         result = list_delete_first(result);
2233         }
2234
2235         return result;
2236 }
2237
2238 /*
2239  * Export the FooIsVisible functions as SQL-callable functions.
2240  */
2241
2242 Datum
2243 pg_table_is_visible(PG_FUNCTION_ARGS)
2244 {
2245         Oid                     oid = PG_GETARG_OID(0);
2246
2247         PG_RETURN_BOOL(RelationIsVisible(oid));
2248 }
2249
2250 Datum
2251 pg_type_is_visible(PG_FUNCTION_ARGS)
2252 {
2253         Oid                     oid = PG_GETARG_OID(0);
2254
2255         PG_RETURN_BOOL(TypeIsVisible(oid));
2256 }
2257
2258 Datum
2259 pg_function_is_visible(PG_FUNCTION_ARGS)
2260 {
2261         Oid                     oid = PG_GETARG_OID(0);
2262
2263         PG_RETURN_BOOL(FunctionIsVisible(oid));
2264 }
2265
2266 Datum
2267 pg_operator_is_visible(PG_FUNCTION_ARGS)
2268 {
2269         Oid                     oid = PG_GETARG_OID(0);
2270
2271         PG_RETURN_BOOL(OperatorIsVisible(oid));
2272 }
2273
2274 Datum
2275 pg_opclass_is_visible(PG_FUNCTION_ARGS)
2276 {
2277         Oid                     oid = PG_GETARG_OID(0);
2278
2279         PG_RETURN_BOOL(OpclassIsVisible(oid));
2280 }
2281
2282 Datum
2283 pg_conversion_is_visible(PG_FUNCTION_ARGS)
2284 {
2285         Oid                     oid = PG_GETARG_OID(0);
2286
2287         PG_RETURN_BOOL(ConversionIsVisible(oid));
2288 }
2289
2290 Datum
2291 pg_my_temp_schema(PG_FUNCTION_ARGS)
2292 {
2293         PG_RETURN_OID(myTempNamespace);
2294 }
2295
2296 Datum
2297 pg_is_other_temp_schema(PG_FUNCTION_ARGS)
2298 {
2299         Oid                     oid = PG_GETARG_OID(0);
2300
2301         PG_RETURN_BOOL(isOtherTempNamespace(oid));
2302 }