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