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