]> granicus.if.org Git - postgresql/blob - src/backend/catalog/namespace.c
Teach autovacuum how to determine whether a temp table belongs to a crashed
[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-2008, 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.107 2008/07/01 02:09:34 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_conversion_fn.h"
28 #include "catalog/pg_namespace.h"
29 #include "catalog/pg_opclass.h"
30 #include "catalog/pg_operator.h"
31 #include "catalog/pg_opfamily.h"
32 #include "catalog/pg_proc.h"
33 #include "catalog/pg_ts_config.h"
34 #include "catalog/pg_ts_dict.h"
35 #include "catalog/pg_ts_parser.h"
36 #include "catalog/pg_ts_template.h"
37 #include "catalog/pg_type.h"
38 #include "commands/dbcommands.h"
39 #include "miscadmin.h"
40 #include "nodes/makefuncs.h"
41 #include "storage/backendid.h"
42 #include "storage/ipc.h"
43 #include "utils/acl.h"
44 #include "utils/builtins.h"
45 #include "utils/guc.h"
46 #include "utils/inval.h"
47 #include "utils/lsyscache.h"
48 #include "utils/memutils.h"
49 #include "utils/rel.h"
50 #include "utils/syscache.h"
51
52
53 /*
54  * The namespace search path is a possibly-empty list of namespace OIDs.
55  * In addition to the explicit list, implicitly-searched namespaces
56  * may be included:
57  *
58  * 1. If a TEMP table namespace has been initialized in this session, it
59  * is implicitly searched first.  (The only time this doesn't happen is
60  * when we are obeying an override search path spec that says not to use the
61  * temp namespace, or the temp namespace is included in the explicit list.)
62  *
63  * 2. The system catalog namespace is always searched.  If the system
64  * namespace is present in the explicit path then it will be searched in
65  * the specified order; otherwise it will be searched after TEMP tables and
66  * *before* the explicit list.  (It might seem that the system namespace
67  * should be implicitly last, but this behavior appears to be required by
68  * SQL99.  Also, this provides a way to search the system namespace first
69  * without thereby making it the default creation target namespace.)
70  *
71  * For security reasons, searches using the search path will ignore the temp
72  * namespace when searching for any object type other than relations and
73  * types.  (We must allow types since temp tables have rowtypes.)
74  *
75  * The default creation target namespace is always the first element of the
76  * explicit list.  If the explicit list is empty, there is no default target.
77  *
78  * The textual specification of search_path can include "$user" to refer to
79  * the namespace named the same as the current user, if any.  (This is just
80  * ignored if there is no such namespace.)      Also, it can include "pg_temp"
81  * to refer to the current backend's temp namespace.  This is usually also
82  * ignorable if the temp namespace hasn't been set up, but there's a special
83  * case: if "pg_temp" appears first then it should be the default creation
84  * target.      We kluge this case a little bit so that the temp namespace isn't
85  * set up until the first attempt to create something in it.  (The reason for
86  * klugery is that we can't create the temp namespace outside a transaction,
87  * but initial GUC processing of search_path happens outside a transaction.)
88  * activeTempCreationPending is TRUE if "pg_temp" appears first in the string
89  * but is not reflected in activeCreationNamespace because the namespace isn't
90  * set up yet.
91  *
92  * In bootstrap mode, the search path is set equal to "pg_catalog", so that
93  * the system namespace is the only one searched or inserted into.
94  * initdb is also careful to set search_path to "pg_catalog" for its
95  * post-bootstrap standalone backend runs.      Otherwise the default search
96  * path is determined by GUC.  The factory default path contains the PUBLIC
97  * namespace (if it exists), preceded by the user's personal namespace
98  * (if one exists).
99  *
100  * We support a stack of "override" search path settings for use within
101  * specific sections of backend code.  namespace_search_path is ignored
102  * whenever the override stack is nonempty.  activeSearchPath is always
103  * the actually active path; it points either to the search list of the
104  * topmost stack entry, or to baseSearchPath which is the list derived
105  * from namespace_search_path.
106  *
107  * If baseSearchPathValid is false, then baseSearchPath (and other
108  * derived variables) need to be recomputed from namespace_search_path.
109  * We mark it invalid upon an assignment to namespace_search_path or receipt
110  * of a syscache invalidation event for pg_namespace.  The recomputation
111  * is done during the next non-overridden lookup attempt.  Note that an
112  * override spec is never subject to recomputation.
113  *
114  * Any namespaces mentioned in namespace_search_path that are not readable
115  * by the current user ID are simply left out of baseSearchPath; so
116  * we have to be willing to recompute the path when current userid changes.
117  * namespaceUser is the userid the path has been computed for.
118  *
119  * Note: all data pointed to by these List variables is in TopMemoryContext.
120  */
121
122 /* These variables define the actually active state: */
123
124 static List *activeSearchPath = NIL;
125
126 /* default place to create stuff; if InvalidOid, no default */
127 static Oid      activeCreationNamespace = InvalidOid;
128
129 /* if TRUE, activeCreationNamespace is wrong, it should be temp namespace */
130 static bool activeTempCreationPending = false;
131
132 /* These variables are the values last derived from namespace_search_path: */
133
134 static List *baseSearchPath = NIL;
135
136 static Oid      baseCreationNamespace = InvalidOid;
137
138 static bool baseTempCreationPending = false;
139
140 static Oid      namespaceUser = InvalidOid;
141
142 /* The above four values are valid only if baseSearchPathValid */
143 static bool baseSearchPathValid = true;
144
145 /* Override requests are remembered in a stack of OverrideStackEntry structs */
146
147 typedef struct
148 {
149         List       *searchPath;         /* the desired search path */
150         Oid                     creationNamespace;              /* the desired creation namespace */
151         int                     nestLevel;              /* subtransaction nesting level */
152 } OverrideStackEntry;
153
154 static List *overrideStack = NIL;
155
156 /*
157  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
158  * in a particular backend session (this happens when a CREATE TEMP TABLE
159  * command is first executed).  Thereafter it's the OID of the temp namespace.
160  *
161  * myTempToastNamespace is the OID of the namespace for my temp tables' toast
162  * tables.      It is set when myTempNamespace is, and is InvalidOid before that.
163  *
164  * myTempNamespaceSubID shows whether we've created the TEMP namespace in the
165  * current subtransaction.      The flag propagates up the subtransaction tree,
166  * so the main transaction will correctly recognize the flag if all
167  * intermediate subtransactions commit.  When it is InvalidSubTransactionId,
168  * we either haven't made the TEMP namespace yet, or have successfully
169  * committed its creation, depending on whether myTempNamespace is valid.
170  */
171 static Oid      myTempNamespace = InvalidOid;
172
173 static Oid      myTempToastNamespace = InvalidOid;
174
175 static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
176
177 /*
178  * This is the user's textual search path specification --- it's the value
179  * of the GUC variable 'search_path'.
180  */
181 char       *namespace_search_path = NULL;
182
183
184 /* Local functions */
185 static void recomputeNamespacePath(void);
186 static void InitTempTableNamespace(void);
187 static void RemoveTempRelations(Oid tempNamespaceId);
188 static void RemoveTempRelationsCallback(int code, Datum arg);
189 static void NamespaceCallback(Datum arg, Oid relid);
190
191 /* These don't really need to appear in any header file */
192 Datum           pg_table_is_visible(PG_FUNCTION_ARGS);
193 Datum           pg_type_is_visible(PG_FUNCTION_ARGS);
194 Datum           pg_function_is_visible(PG_FUNCTION_ARGS);
195 Datum           pg_operator_is_visible(PG_FUNCTION_ARGS);
196 Datum           pg_opclass_is_visible(PG_FUNCTION_ARGS);
197 Datum           pg_conversion_is_visible(PG_FUNCTION_ARGS);
198 Datum           pg_ts_parser_is_visible(PG_FUNCTION_ARGS);
199 Datum           pg_ts_dict_is_visible(PG_FUNCTION_ARGS);
200 Datum           pg_ts_template_is_visible(PG_FUNCTION_ARGS);
201 Datum           pg_ts_config_is_visible(PG_FUNCTION_ARGS);
202 Datum           pg_my_temp_schema(PG_FUNCTION_ARGS);
203 Datum           pg_is_other_temp_schema(PG_FUNCTION_ARGS);
204
205
206 /*
207  * RangeVarGetRelid
208  *              Given a RangeVar describing an existing relation,
209  *              select the proper namespace and look up the relation OID.
210  *
211  * If the relation is not found, return InvalidOid if failOK = true,
212  * otherwise raise an error.
213  */
214 Oid
215 RangeVarGetRelid(const RangeVar *relation, bool failOK)
216 {
217         Oid                     namespaceId;
218         Oid                     relId;
219
220         /*
221          * We check the catalog name and then ignore it.
222          */
223         if (relation->catalogname)
224         {
225                 if (strcmp(relation->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                                                         relation->catalogname, relation->schemaname,
230                                                         relation->relname)));
231         }
232
233         /*
234          * If istemp is set, this is a reference to a temp relation.  The parser
235          * never generates such a RangeVar in simple DML, but it can happen in
236          * contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY KEY)".  Such a
237          * command will generate an added CREATE INDEX operation, which must be
238          * careful to find the temp table, even when pg_temp is not first in the
239          * search path.
240          */
241         if (relation->istemp)
242         {
243                 if (relation->schemaname)
244                         ereport(ERROR,
245                                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
246                                    errmsg("temporary tables cannot specify a schema name")));
247                 if (OidIsValid(myTempNamespace))
248                         relId = get_relname_relid(relation->relname, myTempNamespace);
249                 else    /* this probably can't happen? */
250                         relId = InvalidOid;
251         }
252         else if (relation->schemaname)
253         {
254                 /* use exact schema given */
255                 namespaceId = LookupExplicitNamespace(relation->schemaname);
256                 relId = get_relname_relid(relation->relname, namespaceId);
257         }
258         else
259         {
260                 /* search the namespace path */
261                 relId = RelnameGetRelid(relation->relname);
262         }
263
264         if (!OidIsValid(relId) && !failOK)
265         {
266                 if (relation->schemaname)
267                         ereport(ERROR,
268                                         (errcode(ERRCODE_UNDEFINED_TABLE),
269                                          errmsg("relation \"%s.%s\" does not exist",
270                                                         relation->schemaname, relation->relname)));
271                 else
272                         ereport(ERROR,
273                                         (errcode(ERRCODE_UNDEFINED_TABLE),
274                                          errmsg("relation \"%s\" does not exist",
275                                                         relation->relname)));
276         }
277         return relId;
278 }
279
280 /*
281  * RangeVarGetCreationNamespace
282  *              Given a RangeVar describing a to-be-created relation,
283  *              choose which namespace to create it in.
284  *
285  * Note: calling this may result in a CommandCounterIncrement operation.
286  * That will happen on the first request for a temp table in any particular
287  * backend run; we will need to either create or clean out the temp schema.
288  */
289 Oid
290 RangeVarGetCreationNamespace(const RangeVar *newRelation)
291 {
292         Oid                     namespaceId;
293
294         /*
295          * We check the catalog name and then ignore it.
296          */
297         if (newRelation->catalogname)
298         {
299                 if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
300                         ereport(ERROR,
301                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
302                                          errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
303                                                         newRelation->catalogname, newRelation->schemaname,
304                                                         newRelation->relname)));
305         }
306
307         if (newRelation->istemp)
308         {
309                 /* TEMP tables are created in our backend-local temp namespace */
310                 if (newRelation->schemaname)
311                         ereport(ERROR,
312                                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
313                                    errmsg("temporary tables cannot specify a schema name")));
314                 /* Initialize temp namespace if first time through */
315                 if (!OidIsValid(myTempNamespace))
316                         InitTempTableNamespace();
317                 return myTempNamespace;
318         }
319
320         if (newRelation->schemaname)
321         {
322                 /* check for pg_temp alias */
323                 if (strcmp(newRelation->schemaname, "pg_temp") == 0)
324                 {
325                         /* Initialize temp namespace if first time through */
326                         if (!OidIsValid(myTempNamespace))
327                                 InitTempTableNamespace();
328                         return myTempNamespace;
329                 }
330                 /* use exact schema given */
331                 namespaceId = GetSysCacheOid(NAMESPACENAME,
332                                                                          CStringGetDatum(newRelation->schemaname),
333                                                                          0, 0, 0);
334                 if (!OidIsValid(namespaceId))
335                         ereport(ERROR,
336                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
337                                          errmsg("schema \"%s\" does not exist",
338                                                         newRelation->schemaname)));
339                 /* we do not check for USAGE rights here! */
340         }
341         else
342         {
343                 /* use the default creation namespace */
344                 recomputeNamespacePath();
345                 if (activeTempCreationPending)
346                 {
347                         /* Need to initialize temp namespace */
348                         InitTempTableNamespace();
349                         return myTempNamespace;
350                 }
351                 namespaceId = activeCreationNamespace;
352                 if (!OidIsValid(namespaceId))
353                         ereport(ERROR,
354                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
355                                          errmsg("no schema has been selected to create in")));
356         }
357
358         /* Note: callers will check for CREATE rights when appropriate */
359
360         return namespaceId;
361 }
362
363 /*
364  * RelnameGetRelid
365  *              Try to resolve an unqualified relation name.
366  *              Returns OID if relation found in search path, else InvalidOid.
367  */
368 Oid
369 RelnameGetRelid(const char *relname)
370 {
371         Oid                     relid;
372         ListCell   *l;
373
374         recomputeNamespacePath();
375
376         foreach(l, activeSearchPath)
377         {
378                 Oid                     namespaceId = lfirst_oid(l);
379
380                 relid = get_relname_relid(relname, namespaceId);
381                 if (OidIsValid(relid))
382                         return relid;
383         }
384
385         /* Not found in path */
386         return InvalidOid;
387 }
388
389
390 /*
391  * RelationIsVisible
392  *              Determine whether a relation (identified by OID) is visible in the
393  *              current search path.  Visible means "would be found by searching
394  *              for the unqualified relation name".
395  */
396 bool
397 RelationIsVisible(Oid relid)
398 {
399         HeapTuple       reltup;
400         Form_pg_class relform;
401         Oid                     relnamespace;
402         bool            visible;
403
404         reltup = SearchSysCache(RELOID,
405                                                         ObjectIdGetDatum(relid),
406                                                         0, 0, 0);
407         if (!HeapTupleIsValid(reltup))
408                 elog(ERROR, "cache lookup failed for relation %u", relid);
409         relform = (Form_pg_class) GETSTRUCT(reltup);
410
411         recomputeNamespacePath();
412
413         /*
414          * Quick check: if it ain't in the path at all, it ain't visible. Items in
415          * the system namespace are surely in the path and so we needn't even do
416          * list_member_oid() for them.
417          */
418         relnamespace = relform->relnamespace;
419         if (relnamespace != PG_CATALOG_NAMESPACE &&
420                 !list_member_oid(activeSearchPath, relnamespace))
421                 visible = false;
422         else
423         {
424                 /*
425                  * If it is in the path, it might still not be visible; it could be
426                  * hidden by another relation of the same name earlier in the path. So
427                  * we must do a slow check for conflicting relations.
428                  */
429                 char       *relname = NameStr(relform->relname);
430                 ListCell   *l;
431
432                 visible = false;
433                 foreach(l, activeSearchPath)
434                 {
435                         Oid                     namespaceId = lfirst_oid(l);
436
437                         if (namespaceId == relnamespace)
438                         {
439                                 /* Found it first in path */
440                                 visible = true;
441                                 break;
442                         }
443                         if (OidIsValid(get_relname_relid(relname, namespaceId)))
444                         {
445                                 /* Found something else first in path */
446                                 break;
447                         }
448                 }
449         }
450
451         ReleaseSysCache(reltup);
452
453         return visible;
454 }
455
456
457 /*
458  * TypenameGetTypid
459  *              Try to resolve an unqualified datatype name.
460  *              Returns OID if type found in search path, else InvalidOid.
461  *
462  * This is essentially the same as RelnameGetRelid.
463  */
464 Oid
465 TypenameGetTypid(const char *typname)
466 {
467         Oid                     typid;
468         ListCell   *l;
469
470         recomputeNamespacePath();
471
472         foreach(l, activeSearchPath)
473         {
474                 Oid                     namespaceId = lfirst_oid(l);
475
476                 typid = GetSysCacheOid(TYPENAMENSP,
477                                                            PointerGetDatum(typname),
478                                                            ObjectIdGetDatum(namespaceId),
479                                                            0, 0);
480                 if (OidIsValid(typid))
481                         return typid;
482         }
483
484         /* Not found in path */
485         return InvalidOid;
486 }
487
488 /*
489  * TypeIsVisible
490  *              Determine whether a type (identified by OID) is visible in the
491  *              current search path.  Visible means "would be found by searching
492  *              for the unqualified type name".
493  */
494 bool
495 TypeIsVisible(Oid typid)
496 {
497         HeapTuple       typtup;
498         Form_pg_type typform;
499         Oid                     typnamespace;
500         bool            visible;
501
502         typtup = SearchSysCache(TYPEOID,
503                                                         ObjectIdGetDatum(typid),
504                                                         0, 0, 0);
505         if (!HeapTupleIsValid(typtup))
506                 elog(ERROR, "cache lookup failed for type %u", typid);
507         typform = (Form_pg_type) GETSTRUCT(typtup);
508
509         recomputeNamespacePath();
510
511         /*
512          * Quick check: if it ain't in the path at all, it ain't visible. Items in
513          * the system namespace are surely in the path and so we needn't even do
514          * list_member_oid() for them.
515          */
516         typnamespace = typform->typnamespace;
517         if (typnamespace != PG_CATALOG_NAMESPACE &&
518                 !list_member_oid(activeSearchPath, typnamespace))
519                 visible = false;
520         else
521         {
522                 /*
523                  * If it is in the path, it might still not be visible; it could be
524                  * hidden by another type of the same name earlier in the path. So we
525                  * must do a slow check for conflicting types.
526                  */
527                 char       *typname = NameStr(typform->typname);
528                 ListCell   *l;
529
530                 visible = false;
531                 foreach(l, activeSearchPath)
532                 {
533                         Oid                     namespaceId = lfirst_oid(l);
534
535                         if (namespaceId == typnamespace)
536                         {
537                                 /* Found it first in path */
538                                 visible = true;
539                                 break;
540                         }
541                         if (SearchSysCacheExists(TYPENAMENSP,
542                                                                          PointerGetDatum(typname),
543                                                                          ObjectIdGetDatum(namespaceId),
544                                                                          0, 0))
545                         {
546                                 /* Found something else first in path */
547                                 break;
548                         }
549                 }
550         }
551
552         ReleaseSysCache(typtup);
553
554         return visible;
555 }
556
557
558 /*
559  * FuncnameGetCandidates
560  *              Given a possibly-qualified function name and argument count,
561  *              retrieve a list of the possible matches.
562  *
563  * If nargs is -1, we return all functions matching the given name,
564  * regardless of argument count.
565  *
566  * We search a single namespace if the function name is qualified, else
567  * all namespaces in the search path.  The return list will never contain
568  * multiple entries with identical argument lists --- in the multiple-
569  * namespace case, we arrange for entries in earlier namespaces to mask
570  * identical entries in later namespaces.
571  */
572 FuncCandidateList
573 FuncnameGetCandidates(List *names, int nargs)
574 {
575         FuncCandidateList resultList = NULL;
576         char       *schemaname;
577         char       *funcname;
578         Oid                     namespaceId;
579         CatCList   *catlist;
580         int                     i;
581
582         /* deconstruct the name list */
583         DeconstructQualifiedName(names, &schemaname, &funcname);
584
585         if (schemaname)
586         {
587                 /* use exact schema given */
588                 namespaceId = LookupExplicitNamespace(schemaname);
589         }
590         else
591         {
592                 /* flag to indicate we need namespace search */
593                 namespaceId = InvalidOid;
594                 recomputeNamespacePath();
595         }
596
597         /* Search syscache by name only */
598         catlist = SearchSysCacheList(PROCNAMEARGSNSP, 1,
599                                                                  CStringGetDatum(funcname),
600                                                                  0, 0, 0);
601
602         for (i = 0; i < catlist->n_members; i++)
603         {
604                 HeapTuple       proctup = &catlist->members[i]->tuple;
605                 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
606                 int                     pronargs = procform->pronargs;
607                 int                     pathpos = 0;
608                 FuncCandidateList newResult;
609
610                 /* Ignore if it doesn't match requested argument count */
611                 if (nargs >= 0 && pronargs != nargs)
612                         continue;
613
614                 if (OidIsValid(namespaceId))
615                 {
616                         /* Consider only procs in specified namespace */
617                         if (procform->pronamespace != namespaceId)
618                                 continue;
619                         /* No need to check args, they must all be different */
620                 }
621                 else
622                 {
623                         /*
624                          * Consider only procs that are in the search path and are not in
625                          * the temp namespace.
626                          */
627                         ListCell   *nsp;
628
629                         foreach(nsp, activeSearchPath)
630                         {
631                                 if (procform->pronamespace == lfirst_oid(nsp) &&
632                                         procform->pronamespace != myTempNamespace)
633                                         break;
634                                 pathpos++;
635                         }
636                         if (nsp == NULL)
637                                 continue;               /* proc is not in search path */
638
639                         /*
640                          * Okay, it's in the search path, but does it have the same
641                          * arguments as something we already accepted?  If so, keep only
642                          * the one that appears earlier in the search path.
643                          *
644                          * If we have an ordered list from SearchSysCacheList (the normal
645                          * case), then any conflicting proc must immediately adjoin this
646                          * one in the list, so we only need to look at the newest result
647                          * item.  If we have an unordered list, we have to scan the whole
648                          * result list.
649                          */
650                         if (resultList)
651                         {
652                                 FuncCandidateList prevResult;
653
654                                 if (catlist->ordered)
655                                 {
656                                         if (pronargs == resultList->nargs &&
657                                                 memcmp(procform->proargtypes.values,
658                                                            resultList->args,
659                                                            pronargs * sizeof(Oid)) == 0)
660                                                 prevResult = resultList;
661                                         else
662                                                 prevResult = NULL;
663                                 }
664                                 else
665                                 {
666                                         for (prevResult = resultList;
667                                                  prevResult;
668                                                  prevResult = prevResult->next)
669                                         {
670                                                 if (pronargs == prevResult->nargs &&
671                                                         memcmp(procform->proargtypes.values,
672                                                                    prevResult->args,
673                                                                    pronargs * sizeof(Oid)) == 0)
674                                                         break;
675                                         }
676                                 }
677                                 if (prevResult)
678                                 {
679                                         /* We have a match with a previous result */
680                                         Assert(pathpos != prevResult->pathpos);
681                                         if (pathpos > prevResult->pathpos)
682                                                 continue;               /* keep previous result */
683                                         /* replace previous result */
684                                         prevResult->pathpos = pathpos;
685                                         prevResult->oid = HeapTupleGetOid(proctup);
686                                         continue;       /* args are same, of course */
687                                 }
688                         }
689                 }
690
691                 /*
692                  * Okay to add it to result list
693                  */
694                 newResult = (FuncCandidateList)
695                         palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
696                                    + pronargs * sizeof(Oid));
697                 newResult->pathpos = pathpos;
698                 newResult->oid = HeapTupleGetOid(proctup);
699                 newResult->nargs = pronargs;
700                 memcpy(newResult->args, procform->proargtypes.values,
701                            pronargs * sizeof(Oid));
702
703                 newResult->next = resultList;
704                 resultList = newResult;
705         }
706
707         ReleaseSysCacheList(catlist);
708
709         return resultList;
710 }
711
712 /*
713  * FunctionIsVisible
714  *              Determine whether a function (identified by OID) is visible in the
715  *              current search path.  Visible means "would be found by searching
716  *              for the unqualified function name with exact argument matches".
717  */
718 bool
719 FunctionIsVisible(Oid funcid)
720 {
721         HeapTuple       proctup;
722         Form_pg_proc procform;
723         Oid                     pronamespace;
724         bool            visible;
725
726         proctup = SearchSysCache(PROCOID,
727                                                          ObjectIdGetDatum(funcid),
728                                                          0, 0, 0);
729         if (!HeapTupleIsValid(proctup))
730                 elog(ERROR, "cache lookup failed for function %u", funcid);
731         procform = (Form_pg_proc) GETSTRUCT(proctup);
732
733         recomputeNamespacePath();
734
735         /*
736          * Quick check: if it ain't in the path at all, it ain't visible. Items in
737          * the system namespace are surely in the path and so we needn't even do
738          * list_member_oid() for them.
739          */
740         pronamespace = procform->pronamespace;
741         if (pronamespace != PG_CATALOG_NAMESPACE &&
742                 !list_member_oid(activeSearchPath, pronamespace))
743                 visible = false;
744         else
745         {
746                 /*
747                  * If it is in the path, it might still not be visible; it could be
748                  * hidden by another proc of the same name and arguments earlier in
749                  * the path.  So we must do a slow check to see if this is the same
750                  * proc that would be found by FuncnameGetCandidates.
751                  */
752                 char       *proname = NameStr(procform->proname);
753                 int                     nargs = procform->pronargs;
754                 FuncCandidateList clist;
755
756                 visible = false;
757
758                 clist = FuncnameGetCandidates(list_make1(makeString(proname)), nargs);
759
760                 for (; clist; clist = clist->next)
761                 {
762                         if (memcmp(clist->args, procform->proargtypes.values,
763                                            nargs * sizeof(Oid)) == 0)
764                         {
765                                 /* Found the expected entry; is it the right proc? */
766                                 visible = (clist->oid == funcid);
767                                 break;
768                         }
769                 }
770         }
771
772         ReleaseSysCache(proctup);
773
774         return visible;
775 }
776
777
778 /*
779  * OpernameGetOprid
780  *              Given a possibly-qualified operator name and exact input datatypes,
781  *              look up the operator.  Returns InvalidOid if not found.
782  *
783  * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
784  * a postfix op.
785  *
786  * If the operator name is not schema-qualified, it is sought in the current
787  * namespace search path.
788  */
789 Oid
790 OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
791 {
792         char       *schemaname;
793         char       *opername;
794         CatCList   *catlist;
795         ListCell   *l;
796
797         /* deconstruct the name list */
798         DeconstructQualifiedName(names, &schemaname, &opername);
799
800         if (schemaname)
801         {
802                 /* search only in exact schema given */
803                 Oid                     namespaceId;
804                 HeapTuple       opertup;
805
806                 namespaceId = LookupExplicitNamespace(schemaname);
807                 opertup = SearchSysCache(OPERNAMENSP,
808                                                                  CStringGetDatum(opername),
809                                                                  ObjectIdGetDatum(oprleft),
810                                                                  ObjectIdGetDatum(oprright),
811                                                                  ObjectIdGetDatum(namespaceId));
812                 if (HeapTupleIsValid(opertup))
813                 {
814                         Oid                     result = HeapTupleGetOid(opertup);
815
816                         ReleaseSysCache(opertup);
817                         return result;
818                 }
819                 return InvalidOid;
820         }
821
822         /* Search syscache by name and argument types */
823         catlist = SearchSysCacheList(OPERNAMENSP, 3,
824                                                                  CStringGetDatum(opername),
825                                                                  ObjectIdGetDatum(oprleft),
826                                                                  ObjectIdGetDatum(oprright),
827                                                                  0);
828
829         if (catlist->n_members == 0)
830         {
831                 /* no hope, fall out early */
832                 ReleaseSysCacheList(catlist);
833                 return InvalidOid;
834         }
835
836         /*
837          * We have to find the list member that is first in the search path, if
838          * there's more than one.  This doubly-nested loop looks ugly, but in
839          * practice there should usually be few catlist members.
840          */
841         recomputeNamespacePath();
842
843         foreach(l, activeSearchPath)
844         {
845                 Oid                     namespaceId = lfirst_oid(l);
846                 int                     i;
847
848                 if (namespaceId == myTempNamespace)
849                         continue;                       /* do not look in temp namespace */
850
851                 for (i = 0; i < catlist->n_members; i++)
852                 {
853                         HeapTuple       opertup = &catlist->members[i]->tuple;
854                         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
855
856                         if (operform->oprnamespace == namespaceId)
857                         {
858                                 Oid                     result = HeapTupleGetOid(opertup);
859
860                                 ReleaseSysCacheList(catlist);
861                                 return result;
862                         }
863                 }
864         }
865
866         ReleaseSysCacheList(catlist);
867         return InvalidOid;
868 }
869
870 /*
871  * OpernameGetCandidates
872  *              Given a possibly-qualified operator name and operator kind,
873  *              retrieve a list of the possible matches.
874  *
875  * If oprkind is '\0', we return all operators matching the given name,
876  * regardless of arguments.
877  *
878  * We search a single namespace if the operator name is qualified, else
879  * all namespaces in the search path.  The return list will never contain
880  * multiple entries with identical argument lists --- in the multiple-
881  * namespace case, we arrange for entries in earlier namespaces to mask
882  * identical entries in later namespaces.
883  *
884  * The returned items always have two args[] entries --- one or the other
885  * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
886  */
887 FuncCandidateList
888 OpernameGetCandidates(List *names, char oprkind)
889 {
890         FuncCandidateList resultList = NULL;
891         char       *resultSpace = NULL;
892         int                     nextResult = 0;
893         char       *schemaname;
894         char       *opername;
895         Oid                     namespaceId;
896         CatCList   *catlist;
897         int                     i;
898
899         /* deconstruct the name list */
900         DeconstructQualifiedName(names, &schemaname, &opername);
901
902         if (schemaname)
903         {
904                 /* use exact schema given */
905                 namespaceId = LookupExplicitNamespace(schemaname);
906         }
907         else
908         {
909                 /* flag to indicate we need namespace search */
910                 namespaceId = InvalidOid;
911                 recomputeNamespacePath();
912         }
913
914         /* Search syscache by name only */
915         catlist = SearchSysCacheList(OPERNAMENSP, 1,
916                                                                  CStringGetDatum(opername),
917                                                                  0, 0, 0);
918
919         /*
920          * In typical scenarios, most if not all of the operators found by the
921          * catcache search will end up getting returned; and there can be quite a
922          * few, for common operator names such as '=' or '+'.  To reduce the time
923          * spent in palloc, we allocate the result space as an array large enough
924          * to hold all the operators.  The original coding of this routine did a
925          * separate palloc for each operator, but profiling revealed that the
926          * pallocs used an unreasonably large fraction of parsing time.
927          */
928 #define SPACE_PER_OP MAXALIGN(sizeof(struct _FuncCandidateList) + sizeof(Oid))
929
930         if (catlist->n_members > 0)
931                 resultSpace = palloc(catlist->n_members * SPACE_PER_OP);
932
933         for (i = 0; i < catlist->n_members; i++)
934         {
935                 HeapTuple       opertup = &catlist->members[i]->tuple;
936                 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
937                 int                     pathpos = 0;
938                 FuncCandidateList newResult;
939
940                 /* Ignore operators of wrong kind, if specific kind requested */
941                 if (oprkind && operform->oprkind != oprkind)
942                         continue;
943
944                 if (OidIsValid(namespaceId))
945                 {
946                         /* Consider only opers in specified namespace */
947                         if (operform->oprnamespace != namespaceId)
948                                 continue;
949                         /* No need to check args, they must all be different */
950                 }
951                 else
952                 {
953                         /*
954                          * Consider only opers that are in the search path and are not in
955                          * the temp namespace.
956                          */
957                         ListCell   *nsp;
958
959                         foreach(nsp, activeSearchPath)
960                         {
961                                 if (operform->oprnamespace == lfirst_oid(nsp) &&
962                                         operform->oprnamespace != myTempNamespace)
963                                         break;
964                                 pathpos++;
965                         }
966                         if (nsp == NULL)
967                                 continue;               /* oper is not in search path */
968
969                         /*
970                          * Okay, it's in the search path, but does it have the same
971                          * arguments as something we already accepted?  If so, keep only
972                          * the one that appears earlier in the search path.
973                          *
974                          * If we have an ordered list from SearchSysCacheList (the normal
975                          * case), then any conflicting oper must immediately adjoin this
976                          * one in the list, so we only need to look at the newest result
977                          * item.  If we have an unordered list, we have to scan the whole
978                          * result list.
979                          */
980                         if (resultList)
981                         {
982                                 FuncCandidateList prevResult;
983
984                                 if (catlist->ordered)
985                                 {
986                                         if (operform->oprleft == resultList->args[0] &&
987                                                 operform->oprright == resultList->args[1])
988                                                 prevResult = resultList;
989                                         else
990                                                 prevResult = NULL;
991                                 }
992                                 else
993                                 {
994                                         for (prevResult = resultList;
995                                                  prevResult;
996                                                  prevResult = prevResult->next)
997                                         {
998                                                 if (operform->oprleft == prevResult->args[0] &&
999                                                         operform->oprright == prevResult->args[1])
1000                                                         break;
1001                                         }
1002                                 }
1003                                 if (prevResult)
1004                                 {
1005                                         /* We have a match with a previous result */
1006                                         Assert(pathpos != prevResult->pathpos);
1007                                         if (pathpos > prevResult->pathpos)
1008                                                 continue;               /* keep previous result */
1009                                         /* replace previous result */
1010                                         prevResult->pathpos = pathpos;
1011                                         prevResult->oid = HeapTupleGetOid(opertup);
1012                                         continue;       /* args are same, of course */
1013                                 }
1014                         }
1015                 }
1016
1017                 /*
1018                  * Okay to add it to result list
1019                  */
1020                 newResult = (FuncCandidateList) (resultSpace + nextResult);
1021                 nextResult += SPACE_PER_OP;
1022
1023                 newResult->pathpos = pathpos;
1024                 newResult->oid = HeapTupleGetOid(opertup);
1025                 newResult->nargs = 2;
1026                 newResult->args[0] = operform->oprleft;
1027                 newResult->args[1] = operform->oprright;
1028                 newResult->next = resultList;
1029                 resultList = newResult;
1030         }
1031
1032         ReleaseSysCacheList(catlist);
1033
1034         return resultList;
1035 }
1036
1037 /*
1038  * OperatorIsVisible
1039  *              Determine whether an operator (identified by OID) is visible in the
1040  *              current search path.  Visible means "would be found by searching
1041  *              for the unqualified operator name with exact argument matches".
1042  */
1043 bool
1044 OperatorIsVisible(Oid oprid)
1045 {
1046         HeapTuple       oprtup;
1047         Form_pg_operator oprform;
1048         Oid                     oprnamespace;
1049         bool            visible;
1050
1051         oprtup = SearchSysCache(OPEROID,
1052                                                         ObjectIdGetDatum(oprid),
1053                                                         0, 0, 0);
1054         if (!HeapTupleIsValid(oprtup))
1055                 elog(ERROR, "cache lookup failed for operator %u", oprid);
1056         oprform = (Form_pg_operator) GETSTRUCT(oprtup);
1057
1058         recomputeNamespacePath();
1059
1060         /*
1061          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1062          * the system namespace are surely in the path and so we needn't even do
1063          * list_member_oid() for them.
1064          */
1065         oprnamespace = oprform->oprnamespace;
1066         if (oprnamespace != PG_CATALOG_NAMESPACE &&
1067                 !list_member_oid(activeSearchPath, oprnamespace))
1068                 visible = false;
1069         else
1070         {
1071                 /*
1072                  * If it is in the path, it might still not be visible; it could be
1073                  * hidden by another operator of the same name and arguments earlier
1074                  * in the path.  So we must do a slow check to see if this is the same
1075                  * operator that would be found by OpernameGetOprId.
1076                  */
1077                 char       *oprname = NameStr(oprform->oprname);
1078
1079                 visible = (OpernameGetOprid(list_make1(makeString(oprname)),
1080                                                                         oprform->oprleft, oprform->oprright)
1081                                    == oprid);
1082         }
1083
1084         ReleaseSysCache(oprtup);
1085
1086         return visible;
1087 }
1088
1089
1090 /*
1091  * OpclassnameGetOpcid
1092  *              Try to resolve an unqualified index opclass name.
1093  *              Returns OID if opclass found in search path, else InvalidOid.
1094  *
1095  * This is essentially the same as TypenameGetTypid, but we have to have
1096  * an extra argument for the index AM OID.
1097  */
1098 Oid
1099 OpclassnameGetOpcid(Oid amid, const char *opcname)
1100 {
1101         Oid                     opcid;
1102         ListCell   *l;
1103
1104         recomputeNamespacePath();
1105
1106         foreach(l, activeSearchPath)
1107         {
1108                 Oid                     namespaceId = lfirst_oid(l);
1109
1110                 if (namespaceId == myTempNamespace)
1111                         continue;                       /* do not look in temp namespace */
1112
1113                 opcid = GetSysCacheOid(CLAAMNAMENSP,
1114                                                            ObjectIdGetDatum(amid),
1115                                                            PointerGetDatum(opcname),
1116                                                            ObjectIdGetDatum(namespaceId),
1117                                                            0);
1118                 if (OidIsValid(opcid))
1119                         return opcid;
1120         }
1121
1122         /* Not found in path */
1123         return InvalidOid;
1124 }
1125
1126 /*
1127  * OpclassIsVisible
1128  *              Determine whether an opclass (identified by OID) is visible in the
1129  *              current search path.  Visible means "would be found by searching
1130  *              for the unqualified opclass name".
1131  */
1132 bool
1133 OpclassIsVisible(Oid opcid)
1134 {
1135         HeapTuple       opctup;
1136         Form_pg_opclass opcform;
1137         Oid                     opcnamespace;
1138         bool            visible;
1139
1140         opctup = SearchSysCache(CLAOID,
1141                                                         ObjectIdGetDatum(opcid),
1142                                                         0, 0, 0);
1143         if (!HeapTupleIsValid(opctup))
1144                 elog(ERROR, "cache lookup failed for opclass %u", opcid);
1145         opcform = (Form_pg_opclass) GETSTRUCT(opctup);
1146
1147         recomputeNamespacePath();
1148
1149         /*
1150          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1151          * the system namespace are surely in the path and so we needn't even do
1152          * list_member_oid() for them.
1153          */
1154         opcnamespace = opcform->opcnamespace;
1155         if (opcnamespace != PG_CATALOG_NAMESPACE &&
1156                 !list_member_oid(activeSearchPath, opcnamespace))
1157                 visible = false;
1158         else
1159         {
1160                 /*
1161                  * If it is in the path, it might still not be visible; it could be
1162                  * hidden by another opclass of the same name earlier in the path. So
1163                  * we must do a slow check to see if this opclass would be found by
1164                  * OpclassnameGetOpcid.
1165                  */
1166                 char       *opcname = NameStr(opcform->opcname);
1167
1168                 visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
1169         }
1170
1171         ReleaseSysCache(opctup);
1172
1173         return visible;
1174 }
1175
1176 /*
1177  * OpfamilynameGetOpfid
1178  *              Try to resolve an unqualified index opfamily name.
1179  *              Returns OID if opfamily found in search path, else InvalidOid.
1180  *
1181  * This is essentially the same as TypenameGetTypid, but we have to have
1182  * an extra argument for the index AM OID.
1183  */
1184 Oid
1185 OpfamilynameGetOpfid(Oid amid, const char *opfname)
1186 {
1187         Oid                     opfid;
1188         ListCell   *l;
1189
1190         recomputeNamespacePath();
1191
1192         foreach(l, activeSearchPath)
1193         {
1194                 Oid                     namespaceId = lfirst_oid(l);
1195
1196                 if (namespaceId == myTempNamespace)
1197                         continue;                       /* do not look in temp namespace */
1198
1199                 opfid = GetSysCacheOid(OPFAMILYAMNAMENSP,
1200                                                            ObjectIdGetDatum(amid),
1201                                                            PointerGetDatum(opfname),
1202                                                            ObjectIdGetDatum(namespaceId),
1203                                                            0);
1204                 if (OidIsValid(opfid))
1205                         return opfid;
1206         }
1207
1208         /* Not found in path */
1209         return InvalidOid;
1210 }
1211
1212 /*
1213  * OpfamilyIsVisible
1214  *              Determine whether an opfamily (identified by OID) is visible in the
1215  *              current search path.  Visible means "would be found by searching
1216  *              for the unqualified opfamily name".
1217  */
1218 bool
1219 OpfamilyIsVisible(Oid opfid)
1220 {
1221         HeapTuple       opftup;
1222         Form_pg_opfamily opfform;
1223         Oid                     opfnamespace;
1224         bool            visible;
1225
1226         opftup = SearchSysCache(OPFAMILYOID,
1227                                                         ObjectIdGetDatum(opfid),
1228                                                         0, 0, 0);
1229         if (!HeapTupleIsValid(opftup))
1230                 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
1231         opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
1232
1233         recomputeNamespacePath();
1234
1235         /*
1236          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1237          * the system namespace are surely in the path and so we needn't even do
1238          * list_member_oid() for them.
1239          */
1240         opfnamespace = opfform->opfnamespace;
1241         if (opfnamespace != PG_CATALOG_NAMESPACE &&
1242                 !list_member_oid(activeSearchPath, opfnamespace))
1243                 visible = false;
1244         else
1245         {
1246                 /*
1247                  * If it is in the path, it might still not be visible; it could be
1248                  * hidden by another opfamily of the same name earlier in the path. So
1249                  * we must do a slow check to see if this opfamily would be found by
1250                  * OpfamilynameGetOpfid.
1251                  */
1252                 char       *opfname = NameStr(opfform->opfname);
1253
1254                 visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
1255         }
1256
1257         ReleaseSysCache(opftup);
1258
1259         return visible;
1260 }
1261
1262 /*
1263  * ConversionGetConid
1264  *              Try to resolve an unqualified conversion name.
1265  *              Returns OID if conversion found in search path, else InvalidOid.
1266  *
1267  * This is essentially the same as RelnameGetRelid.
1268  */
1269 Oid
1270 ConversionGetConid(const char *conname)
1271 {
1272         Oid                     conid;
1273         ListCell   *l;
1274
1275         recomputeNamespacePath();
1276
1277         foreach(l, activeSearchPath)
1278         {
1279                 Oid                     namespaceId = lfirst_oid(l);
1280
1281                 if (namespaceId == myTempNamespace)
1282                         continue;                       /* do not look in temp namespace */
1283
1284                 conid = GetSysCacheOid(CONNAMENSP,
1285                                                            PointerGetDatum(conname),
1286                                                            ObjectIdGetDatum(namespaceId),
1287                                                            0, 0);
1288                 if (OidIsValid(conid))
1289                         return conid;
1290         }
1291
1292         /* Not found in path */
1293         return InvalidOid;
1294 }
1295
1296 /*
1297  * ConversionIsVisible
1298  *              Determine whether a conversion (identified by OID) is visible in the
1299  *              current search path.  Visible means "would be found by searching
1300  *              for the unqualified conversion name".
1301  */
1302 bool
1303 ConversionIsVisible(Oid conid)
1304 {
1305         HeapTuple       contup;
1306         Form_pg_conversion conform;
1307         Oid                     connamespace;
1308         bool            visible;
1309
1310         contup = SearchSysCache(CONVOID,
1311                                                         ObjectIdGetDatum(conid),
1312                                                         0, 0, 0);
1313         if (!HeapTupleIsValid(contup))
1314                 elog(ERROR, "cache lookup failed for conversion %u", conid);
1315         conform = (Form_pg_conversion) GETSTRUCT(contup);
1316
1317         recomputeNamespacePath();
1318
1319         /*
1320          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1321          * the system namespace are surely in the path and so we needn't even do
1322          * list_member_oid() for them.
1323          */
1324         connamespace = conform->connamespace;
1325         if (connamespace != PG_CATALOG_NAMESPACE &&
1326                 !list_member_oid(activeSearchPath, connamespace))
1327                 visible = false;
1328         else
1329         {
1330                 /*
1331                  * If it is in the path, it might still not be visible; it could be
1332                  * hidden by another conversion of the same name earlier in the path.
1333                  * So we must do a slow check to see if this conversion would be found
1334                  * by ConversionGetConid.
1335                  */
1336                 char       *conname = NameStr(conform->conname);
1337
1338                 visible = (ConversionGetConid(conname) == conid);
1339         }
1340
1341         ReleaseSysCache(contup);
1342
1343         return visible;
1344 }
1345
1346 /*
1347  * TSParserGetPrsid - find a TS parser by possibly qualified name
1348  *
1349  * If not found, returns InvalidOid if failOK, else throws error
1350  */
1351 Oid
1352 TSParserGetPrsid(List *names, bool failOK)
1353 {
1354         char       *schemaname;
1355         char       *parser_name;
1356         Oid                     namespaceId;
1357         Oid                     prsoid = InvalidOid;
1358         ListCell   *l;
1359
1360         /* deconstruct the name list */
1361         DeconstructQualifiedName(names, &schemaname, &parser_name);
1362
1363         if (schemaname)
1364         {
1365                 /* use exact schema given */
1366                 namespaceId = LookupExplicitNamespace(schemaname);
1367                 prsoid = GetSysCacheOid(TSPARSERNAMENSP,
1368                                                                 PointerGetDatum(parser_name),
1369                                                                 ObjectIdGetDatum(namespaceId),
1370                                                                 0, 0);
1371         }
1372         else
1373         {
1374                 /* search for it in search path */
1375                 recomputeNamespacePath();
1376
1377                 foreach(l, activeSearchPath)
1378                 {
1379                         namespaceId = lfirst_oid(l);
1380
1381                         if (namespaceId == myTempNamespace)
1382                                 continue;               /* do not look in temp namespace */
1383
1384                         prsoid = GetSysCacheOid(TSPARSERNAMENSP,
1385                                                                         PointerGetDatum(parser_name),
1386                                                                         ObjectIdGetDatum(namespaceId),
1387                                                                         0, 0);
1388                         if (OidIsValid(prsoid))
1389                                 break;
1390                 }
1391         }
1392
1393         if (!OidIsValid(prsoid) && !failOK)
1394                 ereport(ERROR,
1395                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1396                                  errmsg("text search parser \"%s\" does not exist",
1397                                                 NameListToString(names))));
1398
1399         return prsoid;
1400 }
1401
1402 /*
1403  * TSParserIsVisible
1404  *              Determine whether a parser (identified by OID) is visible in the
1405  *              current search path.  Visible means "would be found by searching
1406  *              for the unqualified parser name".
1407  */
1408 bool
1409 TSParserIsVisible(Oid prsId)
1410 {
1411         HeapTuple       tup;
1412         Form_pg_ts_parser form;
1413         Oid                     namespace;
1414         bool            visible;
1415
1416         tup = SearchSysCache(TSPARSEROID,
1417                                                  ObjectIdGetDatum(prsId),
1418                                                  0, 0, 0);
1419         if (!HeapTupleIsValid(tup))
1420                 elog(ERROR, "cache lookup failed for text search parser %u", prsId);
1421         form = (Form_pg_ts_parser) GETSTRUCT(tup);
1422
1423         recomputeNamespacePath();
1424
1425         /*
1426          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1427          * the system namespace are surely in the path and so we needn't even do
1428          * list_member_oid() for them.
1429          */
1430         namespace = form->prsnamespace;
1431         if (namespace != PG_CATALOG_NAMESPACE &&
1432                 !list_member_oid(activeSearchPath, namespace))
1433                 visible = false;
1434         else
1435         {
1436                 /*
1437                  * If it is in the path, it might still not be visible; it could be
1438                  * hidden by another parser of the same name earlier in the path. So
1439                  * we must do a slow check for conflicting parsers.
1440                  */
1441                 char       *name = NameStr(form->prsname);
1442                 ListCell   *l;
1443
1444                 visible = false;
1445                 foreach(l, activeSearchPath)
1446                 {
1447                         Oid                     namespaceId = lfirst_oid(l);
1448
1449                         if (namespaceId == myTempNamespace)
1450                                 continue;               /* do not look in temp namespace */
1451
1452                         if (namespaceId == namespace)
1453                         {
1454                                 /* Found it first in path */
1455                                 visible = true;
1456                                 break;
1457                         }
1458                         if (SearchSysCacheExists(TSPARSERNAMENSP,
1459                                                                          PointerGetDatum(name),
1460                                                                          ObjectIdGetDatum(namespaceId),
1461                                                                          0, 0))
1462                         {
1463                                 /* Found something else first in path */
1464                                 break;
1465                         }
1466                 }
1467         }
1468
1469         ReleaseSysCache(tup);
1470
1471         return visible;
1472 }
1473
1474 /*
1475  * TSDictionaryGetDictid - find a TS dictionary by possibly qualified name
1476  *
1477  * If not found, returns InvalidOid if failOK, else throws error
1478  */
1479 Oid
1480 TSDictionaryGetDictid(List *names, bool failOK)
1481 {
1482         char       *schemaname;
1483         char       *dict_name;
1484         Oid                     namespaceId;
1485         Oid                     dictoid = InvalidOid;
1486         ListCell   *l;
1487
1488         /* deconstruct the name list */
1489         DeconstructQualifiedName(names, &schemaname, &dict_name);
1490
1491         if (schemaname)
1492         {
1493                 /* use exact schema given */
1494                 namespaceId = LookupExplicitNamespace(schemaname);
1495                 dictoid = GetSysCacheOid(TSDICTNAMENSP,
1496                                                                  PointerGetDatum(dict_name),
1497                                                                  ObjectIdGetDatum(namespaceId),
1498                                                                  0, 0);
1499         }
1500         else
1501         {
1502                 /* search for it in search path */
1503                 recomputeNamespacePath();
1504
1505                 foreach(l, activeSearchPath)
1506                 {
1507                         namespaceId = lfirst_oid(l);
1508
1509                         if (namespaceId == myTempNamespace)
1510                                 continue;               /* do not look in temp namespace */
1511
1512                         dictoid = GetSysCacheOid(TSDICTNAMENSP,
1513                                                                          PointerGetDatum(dict_name),
1514                                                                          ObjectIdGetDatum(namespaceId),
1515                                                                          0, 0);
1516                         if (OidIsValid(dictoid))
1517                                 break;
1518                 }
1519         }
1520
1521         if (!OidIsValid(dictoid) && !failOK)
1522                 ereport(ERROR,
1523                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1524                                  errmsg("text search dictionary \"%s\" does not exist",
1525                                                 NameListToString(names))));
1526
1527         return dictoid;
1528 }
1529
1530 /*
1531  * TSDictionaryIsVisible
1532  *              Determine whether a dictionary (identified by OID) is visible in the
1533  *              current search path.  Visible means "would be found by searching
1534  *              for the unqualified dictionary name".
1535  */
1536 bool
1537 TSDictionaryIsVisible(Oid dictId)
1538 {
1539         HeapTuple       tup;
1540         Form_pg_ts_dict form;
1541         Oid                     namespace;
1542         bool            visible;
1543
1544         tup = SearchSysCache(TSDICTOID,
1545                                                  ObjectIdGetDatum(dictId),
1546                                                  0, 0, 0);
1547         if (!HeapTupleIsValid(tup))
1548                 elog(ERROR, "cache lookup failed for text search dictionary %u",
1549                          dictId);
1550         form = (Form_pg_ts_dict) GETSTRUCT(tup);
1551
1552         recomputeNamespacePath();
1553
1554         /*
1555          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1556          * the system namespace are surely in the path and so we needn't even do
1557          * list_member_oid() for them.
1558          */
1559         namespace = form->dictnamespace;
1560         if (namespace != PG_CATALOG_NAMESPACE &&
1561                 !list_member_oid(activeSearchPath, namespace))
1562                 visible = false;
1563         else
1564         {
1565                 /*
1566                  * If it is in the path, it might still not be visible; it could be
1567                  * hidden by another dictionary of the same name earlier in the path.
1568                  * So we must do a slow check for conflicting dictionaries.
1569                  */
1570                 char       *name = NameStr(form->dictname);
1571                 ListCell   *l;
1572
1573                 visible = false;
1574                 foreach(l, activeSearchPath)
1575                 {
1576                         Oid                     namespaceId = lfirst_oid(l);
1577
1578                         if (namespaceId == myTempNamespace)
1579                                 continue;               /* do not look in temp namespace */
1580
1581                         if (namespaceId == namespace)
1582                         {
1583                                 /* Found it first in path */
1584                                 visible = true;
1585                                 break;
1586                         }
1587                         if (SearchSysCacheExists(TSDICTNAMENSP,
1588                                                                          PointerGetDatum(name),
1589                                                                          ObjectIdGetDatum(namespaceId),
1590                                                                          0, 0))
1591                         {
1592                                 /* Found something else first in path */
1593                                 break;
1594                         }
1595                 }
1596         }
1597
1598         ReleaseSysCache(tup);
1599
1600         return visible;
1601 }
1602
1603 /*
1604  * TSTemplateGetTmplid - find a TS template by possibly qualified name
1605  *
1606  * If not found, returns InvalidOid if failOK, else throws error
1607  */
1608 Oid
1609 TSTemplateGetTmplid(List *names, bool failOK)
1610 {
1611         char       *schemaname;
1612         char       *template_name;
1613         Oid                     namespaceId;
1614         Oid                     tmploid = InvalidOid;
1615         ListCell   *l;
1616
1617         /* deconstruct the name list */
1618         DeconstructQualifiedName(names, &schemaname, &template_name);
1619
1620         if (schemaname)
1621         {
1622                 /* use exact schema given */
1623                 namespaceId = LookupExplicitNamespace(schemaname);
1624                 tmploid = GetSysCacheOid(TSTEMPLATENAMENSP,
1625                                                                  PointerGetDatum(template_name),
1626                                                                  ObjectIdGetDatum(namespaceId),
1627                                                                  0, 0);
1628         }
1629         else
1630         {
1631                 /* search for it in search path */
1632                 recomputeNamespacePath();
1633
1634                 foreach(l, activeSearchPath)
1635                 {
1636                         namespaceId = lfirst_oid(l);
1637
1638                         if (namespaceId == myTempNamespace)
1639                                 continue;               /* do not look in temp namespace */
1640
1641                         tmploid = GetSysCacheOid(TSTEMPLATENAMENSP,
1642                                                                          PointerGetDatum(template_name),
1643                                                                          ObjectIdGetDatum(namespaceId),
1644                                                                          0, 0);
1645                         if (OidIsValid(tmploid))
1646                                 break;
1647                 }
1648         }
1649
1650         if (!OidIsValid(tmploid) && !failOK)
1651                 ereport(ERROR,
1652                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1653                                  errmsg("text search template \"%s\" does not exist",
1654                                                 NameListToString(names))));
1655
1656         return tmploid;
1657 }
1658
1659 /*
1660  * TSTemplateIsVisible
1661  *              Determine whether a template (identified by OID) is visible in the
1662  *              current search path.  Visible means "would be found by searching
1663  *              for the unqualified template name".
1664  */
1665 bool
1666 TSTemplateIsVisible(Oid tmplId)
1667 {
1668         HeapTuple       tup;
1669         Form_pg_ts_template form;
1670         Oid                     namespace;
1671         bool            visible;
1672
1673         tup = SearchSysCache(TSTEMPLATEOID,
1674                                                  ObjectIdGetDatum(tmplId),
1675                                                  0, 0, 0);
1676         if (!HeapTupleIsValid(tup))
1677                 elog(ERROR, "cache lookup failed for text search template %u", tmplId);
1678         form = (Form_pg_ts_template) GETSTRUCT(tup);
1679
1680         recomputeNamespacePath();
1681
1682         /*
1683          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1684          * the system namespace are surely in the path and so we needn't even do
1685          * list_member_oid() for them.
1686          */
1687         namespace = form->tmplnamespace;
1688         if (namespace != PG_CATALOG_NAMESPACE &&
1689                 !list_member_oid(activeSearchPath, namespace))
1690                 visible = false;
1691         else
1692         {
1693                 /*
1694                  * If it is in the path, it might still not be visible; it could be
1695                  * hidden by another template of the same name earlier in the path. So
1696                  * we must do a slow check for conflicting templates.
1697                  */
1698                 char       *name = NameStr(form->tmplname);
1699                 ListCell   *l;
1700
1701                 visible = false;
1702                 foreach(l, activeSearchPath)
1703                 {
1704                         Oid                     namespaceId = lfirst_oid(l);
1705
1706                         if (namespaceId == myTempNamespace)
1707                                 continue;               /* do not look in temp namespace */
1708
1709                         if (namespaceId == namespace)
1710                         {
1711                                 /* Found it first in path */
1712                                 visible = true;
1713                                 break;
1714                         }
1715                         if (SearchSysCacheExists(TSTEMPLATENAMENSP,
1716                                                                          PointerGetDatum(name),
1717                                                                          ObjectIdGetDatum(namespaceId),
1718                                                                          0, 0))
1719                         {
1720                                 /* Found something else first in path */
1721                                 break;
1722                         }
1723                 }
1724         }
1725
1726         ReleaseSysCache(tup);
1727
1728         return visible;
1729 }
1730
1731 /*
1732  * TSConfigGetCfgid - find a TS config by possibly qualified name
1733  *
1734  * If not found, returns InvalidOid if failOK, else throws error
1735  */
1736 Oid
1737 TSConfigGetCfgid(List *names, bool failOK)
1738 {
1739         char       *schemaname;
1740         char       *config_name;
1741         Oid                     namespaceId;
1742         Oid                     cfgoid = InvalidOid;
1743         ListCell   *l;
1744
1745         /* deconstruct the name list */
1746         DeconstructQualifiedName(names, &schemaname, &config_name);
1747
1748         if (schemaname)
1749         {
1750                 /* use exact schema given */
1751                 namespaceId = LookupExplicitNamespace(schemaname);
1752                 cfgoid = GetSysCacheOid(TSCONFIGNAMENSP,
1753                                                                 PointerGetDatum(config_name),
1754                                                                 ObjectIdGetDatum(namespaceId),
1755                                                                 0, 0);
1756         }
1757         else
1758         {
1759                 /* search for it in search path */
1760                 recomputeNamespacePath();
1761
1762                 foreach(l, activeSearchPath)
1763                 {
1764                         namespaceId = lfirst_oid(l);
1765
1766                         if (namespaceId == myTempNamespace)
1767                                 continue;               /* do not look in temp namespace */
1768
1769                         cfgoid = GetSysCacheOid(TSCONFIGNAMENSP,
1770                                                                         PointerGetDatum(config_name),
1771                                                                         ObjectIdGetDatum(namespaceId),
1772                                                                         0, 0);
1773                         if (OidIsValid(cfgoid))
1774                                 break;
1775                 }
1776         }
1777
1778         if (!OidIsValid(cfgoid) && !failOK)
1779                 ereport(ERROR,
1780                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1781                                  errmsg("text search configuration \"%s\" does not exist",
1782                                                 NameListToString(names))));
1783
1784         return cfgoid;
1785 }
1786
1787 /*
1788  * TSConfigIsVisible
1789  *              Determine whether a text search configuration (identified by OID)
1790  *              is visible in the current search path.  Visible means "would be found
1791  *              by searching for the unqualified text search configuration name".
1792  */
1793 bool
1794 TSConfigIsVisible(Oid cfgid)
1795 {
1796         HeapTuple       tup;
1797         Form_pg_ts_config form;
1798         Oid                     namespace;
1799         bool            visible;
1800
1801         tup = SearchSysCache(TSCONFIGOID,
1802                                                  ObjectIdGetDatum(cfgid),
1803                                                  0, 0, 0);
1804         if (!HeapTupleIsValid(tup))
1805                 elog(ERROR, "cache lookup failed for text search configuration %u",
1806                          cfgid);
1807         form = (Form_pg_ts_config) GETSTRUCT(tup);
1808
1809         recomputeNamespacePath();
1810
1811         /*
1812          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1813          * the system namespace are surely in the path and so we needn't even do
1814          * list_member_oid() for them.
1815          */
1816         namespace = form->cfgnamespace;
1817         if (namespace != PG_CATALOG_NAMESPACE &&
1818                 !list_member_oid(activeSearchPath, namespace))
1819                 visible = false;
1820         else
1821         {
1822                 /*
1823                  * If it is in the path, it might still not be visible; it could be
1824                  * hidden by another configuration of the same name earlier in the
1825                  * path. So we must do a slow check for conflicting configurations.
1826                  */
1827                 char       *name = NameStr(form->cfgname);
1828                 ListCell   *l;
1829
1830                 visible = false;
1831                 foreach(l, activeSearchPath)
1832                 {
1833                         Oid                     namespaceId = lfirst_oid(l);
1834
1835                         if (namespaceId == myTempNamespace)
1836                                 continue;               /* do not look in temp namespace */
1837
1838                         if (namespaceId == namespace)
1839                         {
1840                                 /* Found it first in path */
1841                                 visible = true;
1842                                 break;
1843                         }
1844                         if (SearchSysCacheExists(TSCONFIGNAMENSP,
1845                                                                          PointerGetDatum(name),
1846                                                                          ObjectIdGetDatum(namespaceId),
1847                                                                          0, 0))
1848                         {
1849                                 /* Found something else first in path */
1850                                 break;
1851                         }
1852                 }
1853         }
1854
1855         ReleaseSysCache(tup);
1856
1857         return visible;
1858 }
1859
1860
1861 /*
1862  * DeconstructQualifiedName
1863  *              Given a possibly-qualified name expressed as a list of String nodes,
1864  *              extract the schema name and object name.
1865  *
1866  * *nspname_p is set to NULL if there is no explicit schema name.
1867  */
1868 void
1869 DeconstructQualifiedName(List *names,
1870                                                  char **nspname_p,
1871                                                  char **objname_p)
1872 {
1873         char       *catalogname;
1874         char       *schemaname = NULL;
1875         char       *objname = NULL;
1876
1877         switch (list_length(names))
1878         {
1879                 case 1:
1880                         objname = strVal(linitial(names));
1881                         break;
1882                 case 2:
1883                         schemaname = strVal(linitial(names));
1884                         objname = strVal(lsecond(names));
1885                         break;
1886                 case 3:
1887                         catalogname = strVal(linitial(names));
1888                         schemaname = strVal(lsecond(names));
1889                         objname = strVal(lthird(names));
1890
1891                         /*
1892                          * We check the catalog name and then ignore it.
1893                          */
1894                         if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
1895                                 ereport(ERROR,
1896                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1897                                   errmsg("cross-database references are not implemented: %s",
1898                                                  NameListToString(names))));
1899                         break;
1900                 default:
1901                         ereport(ERROR,
1902                                         (errcode(ERRCODE_SYNTAX_ERROR),
1903                                 errmsg("improper qualified name (too many dotted names): %s",
1904                                            NameListToString(names))));
1905                         break;
1906         }
1907
1908         *nspname_p = schemaname;
1909         *objname_p = objname;
1910 }
1911
1912 /*
1913  * LookupExplicitNamespace
1914  *              Process an explicitly-specified schema name: look up the schema
1915  *              and verify we have USAGE (lookup) rights in it.
1916  *
1917  * Returns the namespace OID.  Raises ereport if any problem.
1918  */
1919 Oid
1920 LookupExplicitNamespace(const char *nspname)
1921 {
1922         Oid                     namespaceId;
1923         AclResult       aclresult;
1924
1925         /* check for pg_temp alias */
1926         if (strcmp(nspname, "pg_temp") == 0)
1927         {
1928                 if (OidIsValid(myTempNamespace))
1929                         return myTempNamespace;
1930
1931                 /*
1932                  * Since this is used only for looking up existing objects, there is
1933                  * no point in trying to initialize the temp namespace here; and doing
1934                  * so might create problems for some callers. Just fall through and
1935                  * give the "does not exist" error.
1936                  */
1937         }
1938
1939         namespaceId = GetSysCacheOid(NAMESPACENAME,
1940                                                                  CStringGetDatum(nspname),
1941                                                                  0, 0, 0);
1942         if (!OidIsValid(namespaceId))
1943                 ereport(ERROR,
1944                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1945                                  errmsg("schema \"%s\" does not exist", nspname)));
1946
1947         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
1948         if (aclresult != ACLCHECK_OK)
1949                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1950                                            nspname);
1951
1952         return namespaceId;
1953 }
1954
1955 /*
1956  * LookupCreationNamespace
1957  *              Look up the schema and verify we have CREATE rights on it.
1958  *
1959  * This is just like LookupExplicitNamespace except for the permission check,
1960  * and that we are willing to create pg_temp if needed.
1961  *
1962  * Note: calling this may result in a CommandCounterIncrement operation,
1963  * if we have to create or clean out the temp namespace.
1964  */
1965 Oid
1966 LookupCreationNamespace(const char *nspname)
1967 {
1968         Oid                     namespaceId;
1969         AclResult       aclresult;
1970
1971         /* check for pg_temp alias */
1972         if (strcmp(nspname, "pg_temp") == 0)
1973         {
1974                 /* Initialize temp namespace if first time through */
1975                 if (!OidIsValid(myTempNamespace))
1976                         InitTempTableNamespace();
1977                 return myTempNamespace;
1978         }
1979
1980         namespaceId = GetSysCacheOid(NAMESPACENAME,
1981                                                                  CStringGetDatum(nspname),
1982                                                                  0, 0, 0);
1983         if (!OidIsValid(namespaceId))
1984                 ereport(ERROR,
1985                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1986                                  errmsg("schema \"%s\" does not exist", nspname)));
1987
1988         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
1989         if (aclresult != ACLCHECK_OK)
1990                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1991                                            nspname);
1992
1993         return namespaceId;
1994 }
1995
1996 /*
1997  * QualifiedNameGetCreationNamespace
1998  *              Given a possibly-qualified name for an object (in List-of-Values
1999  *              format), determine what namespace the object should be created in.
2000  *              Also extract and return the object name (last component of list).
2001  *
2002  * Note: this does not apply any permissions check.  Callers must check
2003  * for CREATE rights on the selected namespace when appropriate.
2004  *
2005  * Note: calling this may result in a CommandCounterIncrement operation,
2006  * if we have to create or clean out the temp namespace.
2007  */
2008 Oid
2009 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
2010 {
2011         char       *schemaname;
2012         Oid                     namespaceId;
2013
2014         /* deconstruct the name list */
2015         DeconstructQualifiedName(names, &schemaname, objname_p);
2016
2017         if (schemaname)
2018         {
2019                 /* check for pg_temp alias */
2020                 if (strcmp(schemaname, "pg_temp") == 0)
2021                 {
2022                         /* Initialize temp namespace if first time through */
2023                         if (!OidIsValid(myTempNamespace))
2024                                 InitTempTableNamespace();
2025                         return myTempNamespace;
2026                 }
2027                 /* use exact schema given */
2028                 namespaceId = GetSysCacheOid(NAMESPACENAME,
2029                                                                          CStringGetDatum(schemaname),
2030                                                                          0, 0, 0);
2031                 if (!OidIsValid(namespaceId))
2032                         ereport(ERROR,
2033                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
2034                                          errmsg("schema \"%s\" does not exist", schemaname)));
2035                 /* we do not check for USAGE rights here! */
2036         }
2037         else
2038         {
2039                 /* use the default creation namespace */
2040                 recomputeNamespacePath();
2041                 if (activeTempCreationPending)
2042                 {
2043                         /* Need to initialize temp namespace */
2044                         InitTempTableNamespace();
2045                         return myTempNamespace;
2046                 }
2047                 namespaceId = activeCreationNamespace;
2048                 if (!OidIsValid(namespaceId))
2049                         ereport(ERROR,
2050                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
2051                                          errmsg("no schema has been selected to create in")));
2052         }
2053
2054         return namespaceId;
2055 }
2056
2057 /*
2058  * makeRangeVarFromNameList
2059  *              Utility routine to convert a qualified-name list into RangeVar form.
2060  */
2061 RangeVar *
2062 makeRangeVarFromNameList(List *names)
2063 {
2064         RangeVar   *rel = makeRangeVar(NULL, NULL);
2065
2066         switch (list_length(names))
2067         {
2068                 case 1:
2069                         rel->relname = strVal(linitial(names));
2070                         break;
2071                 case 2:
2072                         rel->schemaname = strVal(linitial(names));
2073                         rel->relname = strVal(lsecond(names));
2074                         break;
2075                 case 3:
2076                         rel->catalogname = strVal(linitial(names));
2077                         rel->schemaname = strVal(lsecond(names));
2078                         rel->relname = strVal(lthird(names));
2079                         break;
2080                 default:
2081                         ereport(ERROR,
2082                                         (errcode(ERRCODE_SYNTAX_ERROR),
2083                                  errmsg("improper relation name (too many dotted names): %s",
2084                                                 NameListToString(names))));
2085                         break;
2086         }
2087
2088         return rel;
2089 }
2090
2091 /*
2092  * NameListToString
2093  *              Utility routine to convert a qualified-name list into a string.
2094  *
2095  * This is used primarily to form error messages, and so we do not quote
2096  * the list elements, for the sake of legibility.
2097  */
2098 char *
2099 NameListToString(List *names)
2100 {
2101         StringInfoData string;
2102         ListCell   *l;
2103
2104         initStringInfo(&string);
2105
2106         foreach(l, names)
2107         {
2108                 if (l != list_head(names))
2109                         appendStringInfoChar(&string, '.');
2110                 appendStringInfoString(&string, strVal(lfirst(l)));
2111         }
2112
2113         return string.data;
2114 }
2115
2116 /*
2117  * NameListToQuotedString
2118  *              Utility routine to convert a qualified-name list into a string.
2119  *
2120  * Same as above except that names will be double-quoted where necessary,
2121  * so the string could be re-parsed (eg, by textToQualifiedNameList).
2122  */
2123 char *
2124 NameListToQuotedString(List *names)
2125 {
2126         StringInfoData string;
2127         ListCell   *l;
2128
2129         initStringInfo(&string);
2130
2131         foreach(l, names)
2132         {
2133                 if (l != list_head(names))
2134                         appendStringInfoChar(&string, '.');
2135                 appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
2136         }
2137
2138         return string.data;
2139 }
2140
2141 /*
2142  * isTempNamespace - is the given namespace my temporary-table namespace?
2143  */
2144 bool
2145 isTempNamespace(Oid namespaceId)
2146 {
2147         if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
2148                 return true;
2149         return false;
2150 }
2151
2152 /*
2153  * isTempToastNamespace - is the given namespace my temporary-toast-table
2154  *              namespace?
2155  */
2156 bool
2157 isTempToastNamespace(Oid namespaceId)
2158 {
2159         if (OidIsValid(myTempToastNamespace) && myTempToastNamespace == namespaceId)
2160                 return true;
2161         return false;
2162 }
2163
2164 /*
2165  * isTempOrToastNamespace - is the given namespace my temporary-table
2166  *              namespace or my temporary-toast-table namespace?
2167  */
2168 bool
2169 isTempOrToastNamespace(Oid namespaceId)
2170 {
2171         if (OidIsValid(myTempNamespace) &&
2172          (myTempNamespace == namespaceId || myTempToastNamespace == namespaceId))
2173                 return true;
2174         return false;
2175 }
2176
2177 /*
2178  * isAnyTempNamespace - is the given namespace a temporary-table namespace
2179  * (either my own, or another backend's)?  Temporary-toast-table namespaces
2180  * are included, too.
2181  */
2182 bool
2183 isAnyTempNamespace(Oid namespaceId)
2184 {
2185         bool            result;
2186         char       *nspname;
2187
2188         /* True if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
2189         nspname = get_namespace_name(namespaceId);
2190         if (!nspname)
2191                 return false;                   /* no such namespace? */
2192         result = (strncmp(nspname, "pg_temp_", 8) == 0) ||
2193                 (strncmp(nspname, "pg_toast_temp_", 14) == 0);
2194         pfree(nspname);
2195         return result;
2196 }
2197
2198 /*
2199  * isOtherTempNamespace - is the given namespace some other backend's
2200  * temporary-table namespace (including temporary-toast-table namespaces)?
2201  */
2202 bool
2203 isOtherTempNamespace(Oid namespaceId)
2204 {
2205         /* If it's my own temp namespace, say "false" */
2206         if (isTempOrToastNamespace(namespaceId))
2207                 return false;
2208         /* Else, if it's any temp namespace, say "true" */
2209         return isAnyTempNamespace(namespaceId);
2210 }
2211
2212 /*
2213  * GetTempNamespaceBackendId - if the given namespace is a temporary-table
2214  * namespace (either my own, or another backend's), return the BackendId
2215  * that owns it.  Temporary-toast-table namespaces are included, too.
2216  * If it isn't a temp namespace, return -1.
2217  */
2218 int
2219 GetTempNamespaceBackendId(Oid namespaceId)
2220 {
2221         int                     result;
2222         char       *nspname;
2223
2224         /* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
2225         nspname = get_namespace_name(namespaceId);
2226         if (!nspname)
2227                 return -1;                              /* no such namespace? */
2228         if (strncmp(nspname, "pg_temp_", 8) == 0)
2229                 result = atoi(nspname + 8);
2230         else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
2231                 result = atoi(nspname + 14);
2232         else
2233                 result = -1;
2234         pfree(nspname);
2235         return result;
2236 }
2237
2238 /*
2239  * GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
2240  * which must already be assigned.      (This is only used when creating a toast
2241  * table for a temp table, so we must have already done InitTempTableNamespace)
2242  */
2243 Oid
2244 GetTempToastNamespace(void)
2245 {
2246         Assert(OidIsValid(myTempToastNamespace));
2247         return myTempToastNamespace;
2248 }
2249
2250
2251 /*
2252  * GetOverrideSearchPath - fetch current search path definition in form
2253  * used by PushOverrideSearchPath.
2254  *
2255  * The result structure is allocated in the specified memory context
2256  * (which might or might not be equal to CurrentMemoryContext); but any
2257  * junk created by revalidation calculations will be in CurrentMemoryContext.
2258  */
2259 OverrideSearchPath *
2260 GetOverrideSearchPath(MemoryContext context)
2261 {
2262         OverrideSearchPath *result;
2263         List       *schemas;
2264         MemoryContext oldcxt;
2265
2266         recomputeNamespacePath();
2267
2268         oldcxt = MemoryContextSwitchTo(context);
2269
2270         result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
2271         schemas = list_copy(activeSearchPath);
2272         while (schemas && linitial_oid(schemas) != activeCreationNamespace)
2273         {
2274                 if (linitial_oid(schemas) == myTempNamespace)
2275                         result->addTemp = true;
2276                 else
2277                 {
2278                         Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
2279                         result->addCatalog = true;
2280                 }
2281                 schemas = list_delete_first(schemas);
2282         }
2283         result->schemas = schemas;
2284
2285         MemoryContextSwitchTo(oldcxt);
2286
2287         return result;
2288 }
2289
2290 /*
2291  * PushOverrideSearchPath - temporarily override the search path
2292  *
2293  * We allow nested overrides, hence the push/pop terminology.  The GUC
2294  * search_path variable is ignored while an override is active.
2295  */
2296 void
2297 PushOverrideSearchPath(OverrideSearchPath *newpath)
2298 {
2299         OverrideStackEntry *entry;
2300         List       *oidlist;
2301         Oid                     firstNS;
2302         MemoryContext oldcxt;
2303
2304         /*
2305          * Copy the list for safekeeping, and insert implicitly-searched
2306          * namespaces as needed.  This code should track recomputeNamespacePath.
2307          */
2308         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
2309
2310         oidlist = list_copy(newpath->schemas);
2311
2312         /*
2313          * Remember the first member of the explicit list.
2314          */
2315         if (oidlist == NIL)
2316                 firstNS = InvalidOid;
2317         else
2318                 firstNS = linitial_oid(oidlist);
2319
2320         /*
2321          * Add any implicitly-searched namespaces to the list.  Note these go on
2322          * the front, not the back; also notice that we do not check USAGE
2323          * permissions for these.
2324          */
2325         if (newpath->addCatalog)
2326                 oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
2327
2328         if (newpath->addTemp)
2329         {
2330                 Assert(OidIsValid(myTempNamespace));
2331                 oidlist = lcons_oid(myTempNamespace, oidlist);
2332         }
2333
2334         /*
2335          * Build the new stack entry, then insert it at the head of the list.
2336          */
2337         entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
2338         entry->searchPath = oidlist;
2339         entry->creationNamespace = firstNS;
2340         entry->nestLevel = GetCurrentTransactionNestLevel();
2341
2342         overrideStack = lcons(entry, overrideStack);
2343
2344         /* And make it active. */
2345         activeSearchPath = entry->searchPath;
2346         activeCreationNamespace = entry->creationNamespace;
2347         activeTempCreationPending = false;      /* XXX is this OK? */
2348
2349         MemoryContextSwitchTo(oldcxt);
2350 }
2351
2352 /*
2353  * PopOverrideSearchPath - undo a previous PushOverrideSearchPath
2354  *
2355  * Any push during a (sub)transaction will be popped automatically at abort.
2356  * But it's caller error if a push isn't popped in normal control flow.
2357  */
2358 void
2359 PopOverrideSearchPath(void)
2360 {
2361         OverrideStackEntry *entry;
2362
2363         /* Sanity checks. */
2364         if (overrideStack == NIL)
2365                 elog(ERROR, "bogus PopOverrideSearchPath call");
2366         entry = (OverrideStackEntry *) linitial(overrideStack);
2367         if (entry->nestLevel != GetCurrentTransactionNestLevel())
2368                 elog(ERROR, "bogus PopOverrideSearchPath call");
2369
2370         /* Pop the stack and free storage. */
2371         overrideStack = list_delete_first(overrideStack);
2372         list_free(entry->searchPath);
2373         pfree(entry);
2374
2375         /* Activate the next level down. */
2376         if (overrideStack)
2377         {
2378                 entry = (OverrideStackEntry *) linitial(overrideStack);
2379                 activeSearchPath = entry->searchPath;
2380                 activeCreationNamespace = entry->creationNamespace;
2381                 activeTempCreationPending = false;              /* XXX is this OK? */
2382         }
2383         else
2384         {
2385                 /* If not baseSearchPathValid, this is useless but harmless */
2386                 activeSearchPath = baseSearchPath;
2387                 activeCreationNamespace = baseCreationNamespace;
2388                 activeTempCreationPending = baseTempCreationPending;
2389         }
2390 }
2391
2392
2393 /*
2394  * FindConversionByName - find a conversion by possibly qualified name
2395  */
2396 Oid
2397 FindConversionByName(List *name)
2398 {
2399         char       *schemaname;
2400         char       *conversion_name;
2401         Oid                     namespaceId;
2402         Oid                     conoid;
2403         ListCell   *l;
2404
2405         /* deconstruct the name list */
2406         DeconstructQualifiedName(name, &schemaname, &conversion_name);
2407
2408         if (schemaname)
2409         {
2410                 /* use exact schema given */
2411                 namespaceId = LookupExplicitNamespace(schemaname);
2412                 return FindConversion(conversion_name, namespaceId);
2413         }
2414         else
2415         {
2416                 /* search for it in search path */
2417                 recomputeNamespacePath();
2418
2419                 foreach(l, activeSearchPath)
2420                 {
2421                         namespaceId = lfirst_oid(l);
2422
2423                         if (namespaceId == myTempNamespace)
2424                                 continue;               /* do not look in temp namespace */
2425
2426                         conoid = FindConversion(conversion_name, namespaceId);
2427                         if (OidIsValid(conoid))
2428                                 return conoid;
2429                 }
2430         }
2431
2432         /* Not found in path */
2433         return InvalidOid;
2434 }
2435
2436 /*
2437  * FindDefaultConversionProc - find default encoding conversion proc
2438  */
2439 Oid
2440 FindDefaultConversionProc(int4 for_encoding, int4 to_encoding)
2441 {
2442         Oid                     proc;
2443         ListCell   *l;
2444
2445         recomputeNamespacePath();
2446
2447         foreach(l, activeSearchPath)
2448         {
2449                 Oid                     namespaceId = lfirst_oid(l);
2450
2451                 if (namespaceId == myTempNamespace)
2452                         continue;                       /* do not look in temp namespace */
2453
2454                 proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
2455                 if (OidIsValid(proc))
2456                         return proc;
2457         }
2458
2459         /* Not found in path */
2460         return InvalidOid;
2461 }
2462
2463 /*
2464  * recomputeNamespacePath - recompute path derived variables if needed.
2465  */
2466 static void
2467 recomputeNamespacePath(void)
2468 {
2469         Oid                     roleid = GetUserId();
2470         char       *rawname;
2471         List       *namelist;
2472         List       *oidlist;
2473         List       *newpath;
2474         ListCell   *l;
2475         bool            temp_missing;
2476         Oid                     firstNS;
2477         MemoryContext oldcxt;
2478
2479         /* Do nothing if an override search spec is active. */
2480         if (overrideStack)
2481                 return;
2482
2483         /* Do nothing if path is already valid. */
2484         if (baseSearchPathValid && namespaceUser == roleid)
2485                 return;
2486
2487         /* Need a modifiable copy of namespace_search_path string */
2488         rawname = pstrdup(namespace_search_path);
2489
2490         /* Parse string into list of identifiers */
2491         if (!SplitIdentifierString(rawname, ',', &namelist))
2492         {
2493                 /* syntax error in name list */
2494                 /* this should not happen if GUC checked check_search_path */
2495                 elog(ERROR, "invalid list syntax");
2496         }
2497
2498         /*
2499          * Convert the list of names to a list of OIDs.  If any names are not
2500          * recognizable or we don't have read access, just leave them out of the
2501          * list.  (We can't raise an error, since the search_path setting has
2502          * already been accepted.)      Don't make duplicate entries, either.
2503          */
2504         oidlist = NIL;
2505         temp_missing = false;
2506         foreach(l, namelist)
2507         {
2508                 char       *curname = (char *) lfirst(l);
2509                 Oid                     namespaceId;
2510
2511                 if (strcmp(curname, "$user") == 0)
2512                 {
2513                         /* $user --- substitute namespace matching user name, if any */
2514                         HeapTuple       tuple;
2515
2516                         tuple = SearchSysCache(AUTHOID,
2517                                                                    ObjectIdGetDatum(roleid),
2518                                                                    0, 0, 0);
2519                         if (HeapTupleIsValid(tuple))
2520                         {
2521                                 char       *rname;
2522
2523                                 rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
2524                                 namespaceId = GetSysCacheOid(NAMESPACENAME,
2525                                                                                          CStringGetDatum(rname),
2526                                                                                          0, 0, 0);
2527                                 ReleaseSysCache(tuple);
2528                                 if (OidIsValid(namespaceId) &&
2529                                         !list_member_oid(oidlist, namespaceId) &&
2530                                         pg_namespace_aclcheck(namespaceId, roleid,
2531                                                                                   ACL_USAGE) == ACLCHECK_OK)
2532                                         oidlist = lappend_oid(oidlist, namespaceId);
2533                         }
2534                 }
2535                 else if (strcmp(curname, "pg_temp") == 0)
2536                 {
2537                         /* pg_temp --- substitute temp namespace, if any */
2538                         if (OidIsValid(myTempNamespace))
2539                         {
2540                                 if (!list_member_oid(oidlist, myTempNamespace))
2541                                         oidlist = lappend_oid(oidlist, myTempNamespace);
2542                         }
2543                         else
2544                         {
2545                                 /* If it ought to be the creation namespace, set flag */
2546                                 if (oidlist == NIL)
2547                                         temp_missing = true;
2548                         }
2549                 }
2550                 else
2551                 {
2552                         /* normal namespace reference */
2553                         namespaceId = GetSysCacheOid(NAMESPACENAME,
2554                                                                                  CStringGetDatum(curname),
2555                                                                                  0, 0, 0);
2556                         if (OidIsValid(namespaceId) &&
2557                                 !list_member_oid(oidlist, namespaceId) &&
2558                                 pg_namespace_aclcheck(namespaceId, roleid,
2559                                                                           ACL_USAGE) == ACLCHECK_OK)
2560                                 oidlist = lappend_oid(oidlist, namespaceId);
2561                 }
2562         }
2563
2564         /*
2565          * Remember the first member of the explicit list.      (Note: this is
2566          * nominally wrong if temp_missing, but we need it anyway to distinguish
2567          * explicit from implicit mention of pg_catalog.)
2568          */
2569         if (oidlist == NIL)
2570                 firstNS = InvalidOid;
2571         else
2572                 firstNS = linitial_oid(oidlist);
2573
2574         /*
2575          * Add any implicitly-searched namespaces to the list.  Note these go on
2576          * the front, not the back; also notice that we do not check USAGE
2577          * permissions for these.
2578          */
2579         if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
2580                 oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
2581
2582         if (OidIsValid(myTempNamespace) &&
2583                 !list_member_oid(oidlist, myTempNamespace))
2584                 oidlist = lcons_oid(myTempNamespace, oidlist);
2585
2586         /*
2587          * Now that we've successfully built the new list of namespace OIDs, save
2588          * it in permanent storage.
2589          */
2590         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
2591         newpath = list_copy(oidlist);
2592         MemoryContextSwitchTo(oldcxt);
2593
2594         /* Now safe to assign to state variables. */
2595         list_free(baseSearchPath);
2596         baseSearchPath = newpath;
2597         baseCreationNamespace = firstNS;
2598         baseTempCreationPending = temp_missing;
2599
2600         /* Mark the path valid. */
2601         baseSearchPathValid = true;
2602         namespaceUser = roleid;
2603
2604         /* And make it active. */
2605         activeSearchPath = baseSearchPath;
2606         activeCreationNamespace = baseCreationNamespace;
2607         activeTempCreationPending = baseTempCreationPending;
2608
2609         /* Clean up. */
2610         pfree(rawname);
2611         list_free(namelist);
2612         list_free(oidlist);
2613 }
2614
2615 /*
2616  * InitTempTableNamespace
2617  *              Initialize temp table namespace on first use in a particular backend
2618  */
2619 static void
2620 InitTempTableNamespace(void)
2621 {
2622         char            namespaceName[NAMEDATALEN];
2623         Oid                     namespaceId;
2624         Oid                     toastspaceId;
2625
2626         Assert(!OidIsValid(myTempNamespace));
2627
2628         /*
2629          * First, do permission check to see if we are authorized to make temp
2630          * tables.      We use a nonstandard error message here since "databasename:
2631          * permission denied" might be a tad cryptic.
2632          *
2633          * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
2634          * that's necessary since current user ID could change during the session.
2635          * But there's no need to make the namespace in the first place until a
2636          * temp table creation request is made by someone with appropriate rights.
2637          */
2638         if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
2639                                                          ACL_CREATE_TEMP) != ACLCHECK_OK)
2640                 ereport(ERROR,
2641                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2642                                  errmsg("permission denied to create temporary tables in database \"%s\"",
2643                                                 get_database_name(MyDatabaseId))));
2644
2645         snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
2646
2647         namespaceId = GetSysCacheOid(NAMESPACENAME,
2648                                                                  CStringGetDatum(namespaceName),
2649                                                                  0, 0, 0);
2650         if (!OidIsValid(namespaceId))
2651         {
2652                 /*
2653                  * First use of this temp namespace in this database; create it. The
2654                  * temp namespaces are always owned by the superuser.  We leave their
2655                  * permissions at default --- i.e., no access except to superuser ---
2656                  * to ensure that unprivileged users can't peek at other backends'
2657                  * temp tables.  This works because the places that access the temp
2658                  * namespace for my own backend skip permissions checks on it.
2659                  */
2660                 namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
2661                 /* Advance command counter to make namespace visible */
2662                 CommandCounterIncrement();
2663         }
2664         else
2665         {
2666                 /*
2667                  * If the namespace already exists, clean it out (in case the former
2668                  * owner crashed without doing so).
2669                  */
2670                 RemoveTempRelations(namespaceId);
2671         }
2672
2673         /*
2674          * If the corresponding toast-table namespace doesn't exist yet, create it.
2675          * (We assume there is no need to clean it out if it does exist, since
2676          * dropping a parent table should make its toast table go away.)
2677          */
2678         snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d",
2679                          MyBackendId);
2680
2681         toastspaceId = GetSysCacheOid(NAMESPACENAME,
2682                                                                   CStringGetDatum(namespaceName),
2683                                                                   0, 0, 0);
2684         if (!OidIsValid(toastspaceId))
2685         {
2686                 toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
2687                 /* Advance command counter to make namespace visible */
2688                 CommandCounterIncrement();
2689         }
2690
2691         /*
2692          * Okay, we've prepared the temp namespace ... but it's not committed yet,
2693          * so all our work could be undone by transaction rollback.  Set flag for
2694          * AtEOXact_Namespace to know what to do.
2695          */
2696         myTempNamespace = namespaceId;
2697         myTempToastNamespace = toastspaceId;
2698
2699         /* It should not be done already. */
2700         AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
2701         myTempNamespaceSubID = GetCurrentSubTransactionId();
2702
2703         baseSearchPathValid = false;    /* need to rebuild list */
2704 }
2705
2706 /*
2707  * End-of-transaction cleanup for namespaces.
2708  */
2709 void
2710 AtEOXact_Namespace(bool isCommit)
2711 {
2712         /*
2713          * If we abort the transaction in which a temp namespace was selected,
2714          * we'll have to do any creation or cleanout work over again.  So, just
2715          * forget the namespace entirely until next time.  On the other hand, if
2716          * we commit then register an exit callback to clean out the temp tables
2717          * at backend shutdown.  (We only want to register the callback once per
2718          * session, so this is a good place to do it.)
2719          */
2720         if (myTempNamespaceSubID != InvalidSubTransactionId)
2721         {
2722                 if (isCommit)
2723                         on_shmem_exit(RemoveTempRelationsCallback, 0);
2724                 else
2725                 {
2726                         myTempNamespace = InvalidOid;
2727                         myTempToastNamespace = InvalidOid;
2728                         baseSearchPathValid = false;            /* need to rebuild list */
2729                 }
2730                 myTempNamespaceSubID = InvalidSubTransactionId;
2731         }
2732
2733         /*
2734          * Clean up if someone failed to do PopOverrideSearchPath
2735          */
2736         if (overrideStack)
2737         {
2738                 if (isCommit)
2739                         elog(WARNING, "leaked override search path");
2740                 while (overrideStack)
2741                 {
2742                         OverrideStackEntry *entry;
2743
2744                         entry = (OverrideStackEntry *) linitial(overrideStack);
2745                         overrideStack = list_delete_first(overrideStack);
2746                         list_free(entry->searchPath);
2747                         pfree(entry);
2748                 }
2749                 /* If not baseSearchPathValid, this is useless but harmless */
2750                 activeSearchPath = baseSearchPath;
2751                 activeCreationNamespace = baseCreationNamespace;
2752                 activeTempCreationPending = baseTempCreationPending;
2753         }
2754 }
2755
2756 /*
2757  * AtEOSubXact_Namespace
2758  *
2759  * At subtransaction commit, propagate the temp-namespace-creation
2760  * flag to the parent subtransaction.
2761  *
2762  * At subtransaction abort, forget the flag if we set it up.
2763  */
2764 void
2765 AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
2766                                           SubTransactionId parentSubid)
2767 {
2768         OverrideStackEntry *entry;
2769
2770         if (myTempNamespaceSubID == mySubid)
2771         {
2772                 if (isCommit)
2773                         myTempNamespaceSubID = parentSubid;
2774                 else
2775                 {
2776                         myTempNamespaceSubID = InvalidSubTransactionId;
2777                         /* TEMP namespace creation failed, so reset state */
2778                         myTempNamespace = InvalidOid;
2779                         myTempToastNamespace = InvalidOid;
2780                         baseSearchPathValid = false;            /* need to rebuild list */
2781                 }
2782         }
2783
2784         /*
2785          * Clean up if someone failed to do PopOverrideSearchPath
2786          */
2787         while (overrideStack)
2788         {
2789                 entry = (OverrideStackEntry *) linitial(overrideStack);
2790                 if (entry->nestLevel < GetCurrentTransactionNestLevel())
2791                         break;
2792                 if (isCommit)
2793                         elog(WARNING, "leaked override search path");
2794                 overrideStack = list_delete_first(overrideStack);
2795                 list_free(entry->searchPath);
2796                 pfree(entry);
2797         }
2798
2799         /* Activate the next level down. */
2800         if (overrideStack)
2801         {
2802                 entry = (OverrideStackEntry *) linitial(overrideStack);
2803                 activeSearchPath = entry->searchPath;
2804                 activeCreationNamespace = entry->creationNamespace;
2805                 activeTempCreationPending = false;              /* XXX is this OK? */
2806         }
2807         else
2808         {
2809                 /* If not baseSearchPathValid, this is useless but harmless */
2810                 activeSearchPath = baseSearchPath;
2811                 activeCreationNamespace = baseCreationNamespace;
2812                 activeTempCreationPending = baseTempCreationPending;
2813         }
2814 }
2815
2816 /*
2817  * Remove all relations in the specified temp namespace.
2818  *
2819  * This is called at backend shutdown (if we made any temp relations).
2820  * It is also called when we begin using a pre-existing temp namespace,
2821  * in order to clean out any relations that might have been created by
2822  * a crashed backend.
2823  */
2824 static void
2825 RemoveTempRelations(Oid tempNamespaceId)
2826 {
2827         ObjectAddress object;
2828
2829         /*
2830          * We want to get rid of everything in the target namespace, but not the
2831          * namespace itself (deleting it only to recreate it later would be a
2832          * waste of cycles).  We do this by finding everything that has a
2833          * dependency on the namespace.
2834          */
2835         object.classId = NamespaceRelationId;
2836         object.objectId = tempNamespaceId;
2837         object.objectSubId = 0;
2838
2839         deleteWhatDependsOn(&object, false);
2840 }
2841
2842 /*
2843  * Callback to remove temp relations at backend exit.
2844  */
2845 static void
2846 RemoveTempRelationsCallback(int code, Datum arg)
2847 {
2848         if (OidIsValid(myTempNamespace))        /* should always be true */
2849         {
2850                 /* Need to ensure we have a usable transaction. */
2851                 AbortOutOfAnyTransaction();
2852                 StartTransactionCommand();
2853
2854                 RemoveTempRelations(myTempNamespace);
2855
2856                 CommitTransactionCommand();
2857         }
2858 }
2859
2860 /*
2861  * Remove all temp tables from the temporary namespace.
2862  */
2863 void
2864 ResetTempTableNamespace(void)
2865 {
2866         if (OidIsValid(myTempNamespace))
2867                 RemoveTempRelations(myTempNamespace);
2868 }
2869
2870
2871 /*
2872  * Routines for handling the GUC variable 'search_path'.
2873  */
2874
2875 /* assign_hook: validate new search_path, do extra actions as needed */
2876 const char *
2877 assign_search_path(const char *newval, bool doit, GucSource source)
2878 {
2879         char       *rawname;
2880         List       *namelist;
2881         ListCell   *l;
2882
2883         /* Need a modifiable copy of string */
2884         rawname = pstrdup(newval);
2885
2886         /* Parse string into list of identifiers */
2887         if (!SplitIdentifierString(rawname, ',', &namelist))
2888         {
2889                 /* syntax error in name list */
2890                 pfree(rawname);
2891                 list_free(namelist);
2892                 return NULL;
2893         }
2894
2895         /*
2896          * If we aren't inside a transaction, we cannot do database access so
2897          * cannot verify the individual names.  Must accept the list on faith.
2898          */
2899         if (source >= PGC_S_INTERACTIVE && IsTransactionState())
2900         {
2901                 /*
2902                  * Verify that all the names are either valid namespace names or
2903                  * "$user" or "pg_temp".  We do not require $user to correspond to a
2904                  * valid namespace, and pg_temp might not exist yet.  We do not check
2905                  * for USAGE rights, either; should we?
2906                  *
2907                  * When source == PGC_S_TEST, we are checking the argument of an ALTER
2908                  * DATABASE SET or ALTER USER SET command.      It could be that the
2909                  * intended use of the search path is for some other database, so we
2910                  * should not error out if it mentions schemas not present in the
2911                  * current database.  We reduce the message to NOTICE instead.
2912                  */
2913                 foreach(l, namelist)
2914                 {
2915                         char       *curname = (char *) lfirst(l);
2916
2917                         if (strcmp(curname, "$user") == 0)
2918                                 continue;
2919                         if (strcmp(curname, "pg_temp") == 0)
2920                                 continue;
2921                         if (!SearchSysCacheExists(NAMESPACENAME,
2922                                                                           CStringGetDatum(curname),
2923                                                                           0, 0, 0))
2924                                 ereport((source == PGC_S_TEST) ? NOTICE : ERROR,
2925                                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2926                                                  errmsg("schema \"%s\" does not exist", curname)));
2927                 }
2928         }
2929
2930         pfree(rawname);
2931         list_free(namelist);
2932
2933         /*
2934          * We mark the path as needing recomputation, but don't do anything until
2935          * it's needed.  This avoids trying to do database access during GUC
2936          * initialization.
2937          */
2938         if (doit)
2939                 baseSearchPathValid = false;
2940
2941         return newval;
2942 }
2943
2944 /*
2945  * InitializeSearchPath: initialize module during InitPostgres.
2946  *
2947  * This is called after we are up enough to be able to do catalog lookups.
2948  */
2949 void
2950 InitializeSearchPath(void)
2951 {
2952         if (IsBootstrapProcessingMode())
2953         {
2954                 /*
2955                  * In bootstrap mode, the search path must be 'pg_catalog' so that
2956                  * tables are created in the proper namespace; ignore the GUC setting.
2957                  */
2958                 MemoryContext oldcxt;
2959
2960                 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
2961                 baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
2962                 MemoryContextSwitchTo(oldcxt);
2963                 baseCreationNamespace = PG_CATALOG_NAMESPACE;
2964                 baseTempCreationPending = false;
2965                 baseSearchPathValid = true;
2966                 namespaceUser = GetUserId();
2967                 activeSearchPath = baseSearchPath;
2968                 activeCreationNamespace = baseCreationNamespace;
2969                 activeTempCreationPending = baseTempCreationPending;
2970         }
2971         else
2972         {
2973                 /*
2974                  * In normal mode, arrange for a callback on any syscache invalidation
2975                  * of pg_namespace rows.
2976                  */
2977                 CacheRegisterSyscacheCallback(NAMESPACEOID,
2978                                                                           NamespaceCallback,
2979                                                                           (Datum) 0);
2980                 /* Force search path to be recomputed on next use */
2981                 baseSearchPathValid = false;
2982         }
2983 }
2984
2985 /*
2986  * NamespaceCallback
2987  *              Syscache inval callback function
2988  */
2989 static void
2990 NamespaceCallback(Datum arg, Oid relid)
2991 {
2992         /* Force search path to be recomputed on next use */
2993         baseSearchPathValid = false;
2994 }
2995
2996 /*
2997  * Fetch the active search path. The return value is a palloc'ed list
2998  * of OIDs; the caller is responsible for freeing this storage as
2999  * appropriate.
3000  *
3001  * The returned list includes the implicitly-prepended namespaces only if
3002  * includeImplicit is true.
3003  *
3004  * Note: calling this may result in a CommandCounterIncrement operation,
3005  * if we have to create or clean out the temp namespace.
3006  */
3007 List *
3008 fetch_search_path(bool includeImplicit)
3009 {
3010         List       *result;
3011
3012         recomputeNamespacePath();
3013
3014         /*
3015          * If the temp namespace should be first, force it to exist.  This is so
3016          * that callers can trust the result to reflect the actual default
3017          * creation namespace.  It's a bit bogus to do this here, since
3018          * current_schema() is supposedly a stable function without side-effects,
3019          * but the alternatives seem worse.
3020          */
3021         if (activeTempCreationPending)
3022         {
3023                 InitTempTableNamespace();
3024                 recomputeNamespacePath();
3025         }
3026
3027         result = list_copy(activeSearchPath);
3028         if (!includeImplicit)
3029         {
3030                 while (result && linitial_oid(result) != activeCreationNamespace)
3031                         result = list_delete_first(result);
3032         }
3033
3034         return result;
3035 }
3036
3037 /*
3038  * Fetch the active search path into a caller-allocated array of OIDs.
3039  * Returns the number of path entries.  (If this is more than sarray_len,
3040  * then the data didn't fit and is not all stored.)
3041  *
3042  * The returned list always includes the implicitly-prepended namespaces,
3043  * but never includes the temp namespace.  (This is suitable for existing
3044  * users, which would want to ignore the temp namespace anyway.)  This
3045  * definition allows us to not worry about initializing the temp namespace.
3046  */
3047 int
3048 fetch_search_path_array(Oid *sarray, int sarray_len)
3049 {
3050         int                     count = 0;
3051         ListCell   *l;
3052
3053         recomputeNamespacePath();
3054
3055         foreach(l, activeSearchPath)
3056         {
3057                 Oid                     namespaceId = lfirst_oid(l);
3058
3059                 if (namespaceId == myTempNamespace)
3060                         continue;                       /* do not include temp namespace */
3061
3062                 if (count < sarray_len)
3063                         sarray[count] = namespaceId;
3064                 count++;
3065         }
3066
3067         return count;
3068 }
3069
3070
3071 /*
3072  * Export the FooIsVisible functions as SQL-callable functions.
3073  */
3074
3075 Datum
3076 pg_table_is_visible(PG_FUNCTION_ARGS)
3077 {
3078         Oid                     oid = PG_GETARG_OID(0);
3079
3080         PG_RETURN_BOOL(RelationIsVisible(oid));
3081 }
3082
3083 Datum
3084 pg_type_is_visible(PG_FUNCTION_ARGS)
3085 {
3086         Oid                     oid = PG_GETARG_OID(0);
3087
3088         PG_RETURN_BOOL(TypeIsVisible(oid));
3089 }
3090
3091 Datum
3092 pg_function_is_visible(PG_FUNCTION_ARGS)
3093 {
3094         Oid                     oid = PG_GETARG_OID(0);
3095
3096         PG_RETURN_BOOL(FunctionIsVisible(oid));
3097 }
3098
3099 Datum
3100 pg_operator_is_visible(PG_FUNCTION_ARGS)
3101 {
3102         Oid                     oid = PG_GETARG_OID(0);
3103
3104         PG_RETURN_BOOL(OperatorIsVisible(oid));
3105 }
3106
3107 Datum
3108 pg_opclass_is_visible(PG_FUNCTION_ARGS)
3109 {
3110         Oid                     oid = PG_GETARG_OID(0);
3111
3112         PG_RETURN_BOOL(OpclassIsVisible(oid));
3113 }
3114
3115 Datum
3116 pg_conversion_is_visible(PG_FUNCTION_ARGS)
3117 {
3118         Oid                     oid = PG_GETARG_OID(0);
3119
3120         PG_RETURN_BOOL(ConversionIsVisible(oid));
3121 }
3122
3123 Datum
3124 pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
3125 {
3126         Oid                     oid = PG_GETARG_OID(0);
3127
3128         PG_RETURN_BOOL(TSParserIsVisible(oid));
3129 }
3130
3131 Datum
3132 pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
3133 {
3134         Oid                     oid = PG_GETARG_OID(0);
3135
3136         PG_RETURN_BOOL(TSDictionaryIsVisible(oid));
3137 }
3138
3139 Datum
3140 pg_ts_template_is_visible(PG_FUNCTION_ARGS)
3141 {
3142         Oid                     oid = PG_GETARG_OID(0);
3143
3144         PG_RETURN_BOOL(TSTemplateIsVisible(oid));
3145 }
3146
3147 Datum
3148 pg_ts_config_is_visible(PG_FUNCTION_ARGS)
3149 {
3150         Oid                     oid = PG_GETARG_OID(0);
3151
3152         PG_RETURN_BOOL(TSConfigIsVisible(oid));
3153 }
3154
3155 Datum
3156 pg_my_temp_schema(PG_FUNCTION_ARGS)
3157 {
3158         PG_RETURN_OID(myTempNamespace);
3159 }
3160
3161 Datum
3162 pg_is_other_temp_schema(PG_FUNCTION_ARGS)
3163 {
3164         Oid                     oid = PG_GETARG_OID(0);
3165
3166         PG_RETURN_BOOL(isOtherTempNamespace(oid));
3167 }