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