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