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