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