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