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