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