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