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