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