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