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