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