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