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