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