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