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