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