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