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