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