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