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