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