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