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-2018, 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/sinval.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 InitTempTableNamespace(void);
196 static void RemoveTempRelations(Oid tempNamespaceId);
197 static void RemoveTempRelationsCallback(int code, Datum arg);
198 static void NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue);
199 static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
200  int **argnumbers);
201 
202 
203 /*
204  * RangeVarGetRelidExtended
205  * Given a RangeVar describing an existing relation,
206  * select the proper namespace and look up the relation OID.
207  *
208  * If the schema or relation is not found, return InvalidOid if flags contains
209  * RVR_MISSING_OK, otherwise raise an error.
210  *
211  * If flags contains RVR_NOWAIT, throw an error if we'd have to wait for a
212  * lock.
213  *
214  * If flags contains RVR_SKIP_LOCKED, return InvalidOid if we'd have to wait
215  * for a lock.
216  *
217  * flags cannot contain both RVR_NOWAIT and RVR_SKIP_LOCKED.
218  *
219  * Note that if RVR_MISSING_OK and RVR_SKIP_LOCKED are both specified, a
220  * return value of InvalidOid could either mean the relation is missing or it
221  * could not be locked.
222  *
223  * Callback allows caller to check permissions or acquire additional locks
224  * prior to grabbing the relation lock.
225  */
226 Oid
227 RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
228  uint32 flags,
229  RangeVarGetRelidCallback callback, void *callback_arg)
230 {
231  uint64 inval_count;
232  Oid relId;
233  Oid oldRelId = InvalidOid;
234  bool retry = false;
235  bool missing_ok = (flags & RVR_MISSING_OK) != 0;
236 
237  /* verify that flags do no conflict */
238  Assert(!((flags & RVR_NOWAIT) && (flags & RVR_SKIP_LOCKED)));
239 
240  /*
241  * We check the catalog name and then ignore it.
242  */
243  if (relation->catalogname)
244  {
245  if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
246  ereport(ERROR,
247  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
248  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
249  relation->catalogname, relation->schemaname,
250  relation->relname)));
251  }
252 
253  /*
254  * DDL operations can change the results of a name lookup. Since all such
255  * operations will generate invalidation messages, we keep track of
256  * whether any such messages show up while we're performing the operation,
257  * and retry until either (1) no more invalidation messages show up or (2)
258  * the answer doesn't change.
259  *
260  * But if lockmode = NoLock, then we assume that either the caller is OK
261  * with the answer changing under them, or that they already hold some
262  * appropriate lock, and therefore return the first answer we get without
263  * checking for invalidation messages. Also, if the requested lock is
264  * already held, LockRelationOid will not AcceptInvalidationMessages, so
265  * we may fail to notice a change. We could protect against that case by
266  * calling AcceptInvalidationMessages() before beginning this loop, but
267  * that would add a significant amount overhead, so for now we don't.
268  */
269  for (;;)
270  {
271  /*
272  * Remember this value, so that, after looking up the relation name
273  * and locking its OID, we can check whether any invalidation messages
274  * have been processed that might require a do-over.
275  */
276  inval_count = SharedInvalidMessageCounter;
277 
278  /*
279  * Some non-default relpersistence value may have been specified. The
280  * parser never generates such a RangeVar in simple DML, but it can
281  * happen in contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY
282  * KEY)". Such a command will generate an added CREATE INDEX
283  * operation, which must be careful to find the temp table, even when
284  * pg_temp is not first in the search path.
285  */
286  if (relation->relpersistence == RELPERSISTENCE_TEMP)
287  {
289  relId = InvalidOid; /* this probably can't happen? */
290  else
291  {
292  if (relation->schemaname)
293  {
294  Oid namespaceId;
295 
296  namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
297 
298  /*
299  * For missing_ok, allow a non-existent schema name to
300  * return InvalidOid.
301  */
302  if (namespaceId != myTempNamespace)
303  ereport(ERROR,
304  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
305  errmsg("temporary tables cannot specify a schema name")));
306  }
307 
308  relId = get_relname_relid(relation->relname, myTempNamespace);
309  }
310  }
311  else if (relation->schemaname)
312  {
313  Oid namespaceId;
314 
315  /* use exact schema given */
316  namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
317  if (missing_ok && !OidIsValid(namespaceId))
318  relId = InvalidOid;
319  else
320  relId = get_relname_relid(relation->relname, namespaceId);
321  }
322  else
323  {
324  /* search the namespace path */
325  relId = RelnameGetRelid(relation->relname);
326  }
327 
328  /*
329  * Invoke caller-supplied callback, if any.
330  *
331  * This callback is a good place to check permissions: we haven't
332  * taken the table lock yet (and it's really best to check permissions
333  * before locking anything!), but we've gotten far enough to know what
334  * OID we think we should lock. Of course, concurrent DDL might
335  * change things while we're waiting for the lock, but in that case
336  * the callback will be invoked again for the new OID.
337  */
338  if (callback)
339  callback(relation, relId, oldRelId, callback_arg);
340 
341  /*
342  * If no lock requested, we assume the caller knows what they're
343  * doing. They should have already acquired a heavyweight lock on
344  * this relation earlier in the processing of this same statement, so
345  * it wouldn't be appropriate to AcceptInvalidationMessages() here, as
346  * that might pull the rug out from under them.
347  */
348  if (lockmode == NoLock)
349  break;
350 
351  /*
352  * If, upon retry, we get back the same OID we did last time, then the
353  * invalidation messages we processed did not change the final answer.
354  * So we're done.
355  *
356  * If we got a different OID, we've locked the relation that used to
357  * have this name rather than the one that does now. So release the
358  * lock.
359  */
360  if (retry)
361  {
362  if (relId == oldRelId)
363  break;
364  if (OidIsValid(oldRelId))
365  UnlockRelationOid(oldRelId, lockmode);
366  }
367 
368  /*
369  * Lock relation. This will also accept any pending invalidation
370  * messages. If we got back InvalidOid, indicating not found, then
371  * there's nothing to lock, but we accept invalidation messages
372  * anyway, to flush any negative catcache entries that may be
373  * lingering.
374  */
375  if (!OidIsValid(relId))
377  else if (!(flags & (RVR_NOWAIT | RVR_SKIP_LOCKED)))
378  LockRelationOid(relId, lockmode);
379  else if (!ConditionalLockRelationOid(relId, lockmode))
380  {
381  int elevel = (flags & RVR_SKIP_LOCKED) ? DEBUG1 : ERROR;
382 
383  if (relation->schemaname)
384  ereport(elevel,
385  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
386  errmsg("could not obtain lock on relation \"%s.%s\"",
387  relation->schemaname, relation->relname)));
388  else
389  ereport(elevel,
390  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
391  errmsg("could not obtain lock on relation \"%s\"",
392  relation->relname)));
393 
394  return InvalidOid;
395  }
396 
397  /*
398  * If no invalidation message were processed, we're done!
399  */
400  if (inval_count == SharedInvalidMessageCounter)
401  break;
402 
403  /*
404  * Something may have changed. Let's repeat the name lookup, to make
405  * sure this name still references the same relation it did
406  * previously.
407  */
408  retry = true;
409  oldRelId = relId;
410  }
411 
412  if (!OidIsValid(relId))
413  {
414  int elevel = missing_ok ? DEBUG1 : ERROR;
415 
416  if (relation->schemaname)
417  ereport(elevel,
419  errmsg("relation \"%s.%s\" does not exist",
420  relation->schemaname, relation->relname)));
421  else
422  ereport(elevel,
424  errmsg("relation \"%s\" does not exist",
425  relation->relname)));
426  }
427  return relId;
428 }
429 
430 /*
431  * RangeVarGetCreationNamespace
432  * Given a RangeVar describing a to-be-created relation,
433  * choose which namespace to create it in.
434  *
435  * Note: calling this may result in a CommandCounterIncrement operation.
436  * That will happen on the first request for a temp table in any particular
437  * backend run; we will need to either create or clean out the temp schema.
438  */
439 Oid
441 {
442  Oid namespaceId;
443 
444  /*
445  * We check the catalog name and then ignore it.
446  */
447  if (newRelation->catalogname)
448  {
449  if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
450  ereport(ERROR,
451  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
452  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
453  newRelation->catalogname, newRelation->schemaname,
454  newRelation->relname)));
455  }
456 
457  if (newRelation->schemaname)
458  {
459  /* check for pg_temp alias */
460  if (strcmp(newRelation->schemaname, "pg_temp") == 0)
461  {
462  /* Initialize temp namespace if first time through */
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 if first time through */
476  return myTempNamespace;
477  }
478  else
479  {
480  /* use the default creation namespace */
483  {
484  /* Need to initialize temp namespace */
486  return myTempNamespace;
487  }
488  namespaceId = activeCreationNamespace;
489  if (!OidIsValid(namespaceId))
490  ereport(ERROR,
491  (errcode(ERRCODE_UNDEFINED_SCHEMA),
492  errmsg("no schema has been selected to create in")));
493  }
494 
495  /* Note: callers will check for CREATE rights when appropriate */
496 
497  return namespaceId;
498 }
499 
500 /*
501  * RangeVarGetAndCheckCreationNamespace
502  *
503  * This function returns the OID of the namespace in which a new relation
504  * with a given name should be created. If the user does not have CREATE
505  * permission on the target namespace, this function will instead signal
506  * an ERROR.
507  *
508  * If non-NULL, *existing_oid is set to the OID of any existing relation with
509  * the same name which already exists in that namespace, or to InvalidOid if
510  * no such relation exists.
511  *
512  * If lockmode != NoLock, the specified lock mode is acquired on the existing
513  * relation, if any, provided that the current user owns the target relation.
514  * However, if lockmode != NoLock and the user does not own the target
515  * relation, we throw an ERROR, as we must not try to lock relations the
516  * user does not have permissions on.
517  *
518  * As a side effect, this function acquires AccessShareLock on the target
519  * namespace. Without this, the namespace could be dropped before our
520  * transaction commits, leaving behind relations with relnamespace pointing
521  * to a no-longer-existent namespace.
522  *
523  * As a further side-effect, if the selected namespace is a temporary namespace,
524  * we mark the RangeVar as RELPERSISTENCE_TEMP.
525  */
526 Oid
528  LOCKMODE lockmode,
529  Oid *existing_relation_id)
530 {
531  uint64 inval_count;
532  Oid relid;
533  Oid oldrelid = InvalidOid;
534  Oid nspid;
535  Oid oldnspid = InvalidOid;
536  bool retry = false;
537 
538  /*
539  * We check the catalog name and then ignore it.
540  */
541  if (relation->catalogname)
542  {
543  if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
544  ereport(ERROR,
545  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
546  errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
547  relation->catalogname, relation->schemaname,
548  relation->relname)));
549  }
550 
551  /*
552  * As in RangeVarGetRelidExtended(), we guard against concurrent DDL
553  * operations by tracking whether any invalidation messages are processed
554  * while we're doing the name lookups and acquiring locks. See comments
555  * in that function for a more detailed explanation of this logic.
556  */
557  for (;;)
558  {
559  AclResult aclresult;
560 
561  inval_count = SharedInvalidMessageCounter;
562 
563  /* Look up creation namespace and check for existing relation. */
564  nspid = RangeVarGetCreationNamespace(relation);
565  Assert(OidIsValid(nspid));
566  if (existing_relation_id != NULL)
567  relid = get_relname_relid(relation->relname, nspid);
568  else
569  relid = InvalidOid;
570 
571  /*
572  * In bootstrap processing mode, we don't bother with permissions or
573  * locking. Permissions might not be working yet, and locking is
574  * unnecessary.
575  */
577  break;
578 
579  /* Check namespace permissions. */
580  aclresult = pg_namespace_aclcheck(nspid, GetUserId(), ACL_CREATE);
581  if (aclresult != ACLCHECK_OK)
582  aclcheck_error(aclresult, OBJECT_SCHEMA,
583  get_namespace_name(nspid));
584 
585  if (retry)
586  {
587  /* If nothing changed, we're done. */
588  if (relid == oldrelid && nspid == oldnspid)
589  break;
590  /* If creation namespace has changed, give up old lock. */
591  if (nspid != oldnspid)
592  UnlockDatabaseObject(NamespaceRelationId, oldnspid, 0,
594  /* If name points to something different, give up old lock. */
595  if (relid != oldrelid && OidIsValid(oldrelid) && lockmode != NoLock)
596  UnlockRelationOid(oldrelid, lockmode);
597  }
598 
599  /* Lock namespace. */
600  if (nspid != oldnspid)
601  LockDatabaseObject(NamespaceRelationId, nspid, 0, AccessShareLock);
602 
603  /* Lock relation, if required if and we have permission. */
604  if (lockmode != NoLock && OidIsValid(relid))
605  {
606  if (!pg_class_ownercheck(relid, GetUserId()))
608  relation->relname);
609  if (relid != oldrelid)
610  LockRelationOid(relid, lockmode);
611  }
612 
613  /* If no invalidation message were processed, we're done! */
614  if (inval_count == SharedInvalidMessageCounter)
615  break;
616 
617  /* Something may have changed, so recheck our work. */
618  retry = true;
619  oldrelid = relid;
620  oldnspid = nspid;
621  }
622 
623  RangeVarAdjustRelationPersistence(relation, nspid);
624  if (existing_relation_id != NULL)
625  *existing_relation_id = relid;
626  return nspid;
627 }
628 
629 /*
630  * Adjust the relpersistence for an about-to-be-created relation based on the
631  * creation namespace, and throw an error for invalid combinations.
632  */
633 void
635 {
636  switch (newRelation->relpersistence)
637  {
638  case RELPERSISTENCE_TEMP:
639  if (!isTempOrTempToastNamespace(nspid))
640  {
641  if (isAnyTempNamespace(nspid))
642  ereport(ERROR,
643  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
644  errmsg("cannot create relations in temporary schemas of other sessions")));
645  else
646  ereport(ERROR,
647  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
648  errmsg("cannot create temporary relation in non-temporary schema")));
649  }
650  break;
651  case RELPERSISTENCE_PERMANENT:
652  if (isTempOrTempToastNamespace(nspid))
653  newRelation->relpersistence = RELPERSISTENCE_TEMP;
654  else if (isAnyTempNamespace(nspid))
655  ereport(ERROR,
656  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
657  errmsg("cannot create relations in temporary schemas of other sessions")));
658  break;
659  default:
660  if (isAnyTempNamespace(nspid))
661  ereport(ERROR,
662  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
663  errmsg("only temporary relations may be created in temporary schemas")));
664  }
665 }
666 
667 /*
668  * RelnameGetRelid
669  * Try to resolve an unqualified relation name.
670  * Returns OID if relation found in search path, else InvalidOid.
671  */
672 Oid
673 RelnameGetRelid(const char *relname)
674 {
675  Oid relid;
676  ListCell *l;
677 
679 
680  foreach(l, activeSearchPath)
681  {
682  Oid namespaceId = lfirst_oid(l);
683 
684  relid = get_relname_relid(relname, namespaceId);
685  if (OidIsValid(relid))
686  return relid;
687  }
688 
689  /* Not found in path */
690  return InvalidOid;
691 }
692 
693 
694 /*
695  * RelationIsVisible
696  * Determine whether a relation (identified by OID) is visible in the
697  * current search path. Visible means "would be found by searching
698  * for the unqualified relation name".
699  */
700 bool
702 {
703  HeapTuple reltup;
704  Form_pg_class relform;
706  bool visible;
707 
708  reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
709  if (!HeapTupleIsValid(reltup))
710  elog(ERROR, "cache lookup failed for relation %u", relid);
711  relform = (Form_pg_class) GETSTRUCT(reltup);
712 
714 
715  /*
716  * Quick check: if it ain't in the path at all, it ain't visible. Items in
717  * the system namespace are surely in the path and so we needn't even do
718  * list_member_oid() for them.
719  */
720  relnamespace = relform->relnamespace;
721  if (relnamespace != PG_CATALOG_NAMESPACE &&
722  !list_member_oid(activeSearchPath, relnamespace))
723  visible = false;
724  else
725  {
726  /*
727  * If it is in the path, it might still not be visible; it could be
728  * hidden by another relation of the same name earlier in the path. So
729  * we must do a slow check for conflicting relations.
730  */
731  char *relname = NameStr(relform->relname);
732  ListCell *l;
733 
734  visible = false;
735  foreach(l, activeSearchPath)
736  {
737  Oid namespaceId = lfirst_oid(l);
738 
739  if (namespaceId == relnamespace)
740  {
741  /* Found it first in path */
742  visible = true;
743  break;
744  }
745  if (OidIsValid(get_relname_relid(relname, namespaceId)))
746  {
747  /* Found something else first in path */
748  break;
749  }
750  }
751  }
752 
753  ReleaseSysCache(reltup);
754 
755  return visible;
756 }
757 
758 
759 /*
760  * TypenameGetTypid
761  * Try to resolve an unqualified datatype name.
762  * Returns OID if type found in search path, else InvalidOid.
763  *
764  * This is essentially the same as RelnameGetRelid.
765  */
766 Oid
767 TypenameGetTypid(const char *typname)
768 {
769  Oid typid;
770  ListCell *l;
771 
773 
774  foreach(l, activeSearchPath)
775  {
776  Oid namespaceId = lfirst_oid(l);
777 
779  PointerGetDatum(typname),
780  ObjectIdGetDatum(namespaceId));
781  if (OidIsValid(typid))
782  return typid;
783  }
784 
785  /* Not found in path */
786  return InvalidOid;
787 }
788 
789 /*
790  * TypeIsVisible
791  * Determine whether a type (identified by OID) is visible in the
792  * current search path. Visible means "would be found by searching
793  * for the unqualified type name".
794  */
795 bool
797 {
798  HeapTuple typtup;
799  Form_pg_type typform;
800  Oid typnamespace;
801  bool visible;
802 
803  typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
804  if (!HeapTupleIsValid(typtup))
805  elog(ERROR, "cache lookup failed for type %u", typid);
806  typform = (Form_pg_type) GETSTRUCT(typtup);
807 
809 
810  /*
811  * Quick check: if it ain't in the path at all, it ain't visible. Items in
812  * the system namespace are surely in the path and so we needn't even do
813  * list_member_oid() for them.
814  */
815  typnamespace = typform->typnamespace;
816  if (typnamespace != PG_CATALOG_NAMESPACE &&
817  !list_member_oid(activeSearchPath, typnamespace))
818  visible = false;
819  else
820  {
821  /*
822  * If it is in the path, it might still not be visible; it could be
823  * hidden by another type of the same name earlier in the path. So we
824  * must do a slow check for conflicting types.
825  */
826  char *typname = NameStr(typform->typname);
827  ListCell *l;
828 
829  visible = false;
830  foreach(l, activeSearchPath)
831  {
832  Oid namespaceId = lfirst_oid(l);
833 
834  if (namespaceId == typnamespace)
835  {
836  /* Found it first in path */
837  visible = true;
838  break;
839  }
841  PointerGetDatum(typname),
842  ObjectIdGetDatum(namespaceId)))
843  {
844  /* Found something else first in path */
845  break;
846  }
847  }
848  }
849 
850  ReleaseSysCache(typtup);
851 
852  return visible;
853 }
854 
855 
856 /*
857  * FuncnameGetCandidates
858  * Given a possibly-qualified function name and argument count,
859  * retrieve a list of the possible matches.
860  *
861  * If nargs is -1, we return all functions matching the given name,
862  * regardless of argument count. (argnames must be NIL, and expand_variadic
863  * and expand_defaults must be false, in this case.)
864  *
865  * If argnames isn't NIL, we are considering a named- or mixed-notation call,
866  * and only functions having all the listed argument names will be returned.
867  * (We assume that length(argnames) <= nargs and all the passed-in names are
868  * distinct.) The returned structs will include an argnumbers array showing
869  * the actual argument index for each logical argument position.
870  *
871  * If expand_variadic is true, then variadic functions having the same number
872  * or fewer arguments will be retrieved, with the variadic argument and any
873  * additional argument positions filled with the variadic element type.
874  * nvargs in the returned struct is set to the number of such arguments.
875  * If expand_variadic is false, variadic arguments are not treated specially,
876  * and the returned nvargs will always be zero.
877  *
878  * If expand_defaults is true, functions that could match after insertion of
879  * default argument values will also be retrieved. In this case the returned
880  * structs could have nargs > passed-in nargs, and ndargs is set to the number
881  * of additional args (which can be retrieved from the function's
882  * proargdefaults entry).
883  *
884  * It is not possible for nvargs and ndargs to both be nonzero in the same
885  * list entry, since default insertion allows matches to functions with more
886  * than nargs arguments while the variadic transformation requires the same
887  * number or less.
888  *
889  * When argnames isn't NIL, the returned args[] type arrays are not ordered
890  * according to the functions' declarations, but rather according to the call:
891  * first any positional arguments, then the named arguments, then defaulted
892  * arguments (if needed and allowed by expand_defaults). The argnumbers[]
893  * array can be used to map this back to the catalog information.
894  * argnumbers[k] is set to the proargtypes index of the k'th call argument.
895  *
896  * We search a single namespace if the function name is qualified, else
897  * all namespaces in the search path. In the multiple-namespace case,
898  * we arrange for entries in earlier namespaces to mask identical entries in
899  * later namespaces.
900  *
901  * When expanding variadics, we arrange for non-variadic functions to mask
902  * variadic ones if the expanded argument list is the same. It is still
903  * possible for there to be conflicts between different variadic functions,
904  * however.
905  *
906  * It is guaranteed that the return list will never contain multiple entries
907  * with identical argument lists. When expand_defaults is true, the entries
908  * could have more than nargs positions, but we still guarantee that they are
909  * distinct in the first nargs positions. However, if argnames isn't NIL or
910  * either expand_variadic or expand_defaults is true, there might be multiple
911  * candidate functions that expand to identical argument lists. Rather than
912  * throw error here, we report such situations by returning a single entry
913  * with oid = 0 that represents a set of such conflicting candidates.
914  * The caller might end up discarding such an entry anyway, but if it selects
915  * such an entry it should react as though the call were ambiguous.
916  *
917  * If missing_ok is true, an empty list (NULL) is returned if the name was
918  * schema- qualified with a schema that does not exist. Likewise if no
919  * candidate is found for other reasons.
920  */
922 FuncnameGetCandidates(List *names, int nargs, List *argnames,
923  bool expand_variadic, bool expand_defaults,
924  bool missing_ok)
925 {
926  FuncCandidateList resultList = NULL;
927  bool any_special = false;
928  char *schemaname;
929  char *funcname;
930  Oid namespaceId;
931  CatCList *catlist;
932  int i;
933 
934  /* check for caller error */
935  Assert(nargs >= 0 || !(expand_variadic | expand_defaults));
936 
937  /* deconstruct the name list */
938  DeconstructQualifiedName(names, &schemaname, &funcname);
939 
940  if (schemaname)
941  {
942  /* use exact schema given */
943  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
944  if (!OidIsValid(namespaceId))
945  return NULL;
946  }
947  else
948  {
949  /* flag to indicate we need namespace search */
950  namespaceId = InvalidOid;
952  }
953 
954  /* Search syscache by name only */
956 
957  for (i = 0; i < catlist->n_members; i++)
958  {
959  HeapTuple proctup = &catlist->members[i]->tuple;
960  Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
961  int pronargs = procform->pronargs;
962  int effective_nargs;
963  int pathpos = 0;
964  bool variadic;
965  bool use_defaults;
966  Oid va_elem_type;
967  int *argnumbers = NULL;
968  FuncCandidateList newResult;
969 
970  if (OidIsValid(namespaceId))
971  {
972  /* Consider only procs in specified namespace */
973  if (procform->pronamespace != namespaceId)
974  continue;
975  }
976  else
977  {
978  /*
979  * Consider only procs that are in the search path and are not in
980  * the temp namespace.
981  */
982  ListCell *nsp;
983 
984  foreach(nsp, activeSearchPath)
985  {
986  if (procform->pronamespace == lfirst_oid(nsp) &&
987  procform->pronamespace != myTempNamespace)
988  break;
989  pathpos++;
990  }
991  if (nsp == NULL)
992  continue; /* proc is not in search path */
993  }
994 
995  if (argnames != NIL)
996  {
997  /*
998  * Call uses named or mixed notation
999  *
1000  * Named or mixed notation can match a variadic function only if
1001  * expand_variadic is off; otherwise there is no way to match the
1002  * presumed-nameless parameters expanded from the variadic array.
1003  */
1004  if (OidIsValid(procform->provariadic) && expand_variadic)
1005  continue;
1006  va_elem_type = InvalidOid;
1007  variadic = false;
1008 
1009  /*
1010  * Check argument count.
1011  */
1012  Assert(nargs >= 0); /* -1 not supported with argnames */
1013 
1014  if (pronargs > nargs && expand_defaults)
1015  {
1016  /* Ignore if not enough default expressions */
1017  if (nargs + procform->pronargdefaults < pronargs)
1018  continue;
1019  use_defaults = true;
1020  }
1021  else
1022  use_defaults = false;
1023 
1024  /* Ignore if it doesn't match requested argument count */
1025  if (pronargs != nargs && !use_defaults)
1026  continue;
1027 
1028  /* Check for argument name match, generate positional mapping */
1029  if (!MatchNamedCall(proctup, nargs, argnames,
1030  &argnumbers))
1031  continue;
1032 
1033  /* Named argument matching is always "special" */
1034  any_special = true;
1035  }
1036  else
1037  {
1038  /*
1039  * Call uses positional notation
1040  *
1041  * Check if function is variadic, and get variadic element type if
1042  * so. If expand_variadic is false, we should just ignore
1043  * variadic-ness.
1044  */
1045  if (pronargs <= nargs && expand_variadic)
1046  {
1047  va_elem_type = procform->provariadic;
1048  variadic = OidIsValid(va_elem_type);
1049  any_special |= variadic;
1050  }
1051  else
1052  {
1053  va_elem_type = InvalidOid;
1054  variadic = false;
1055  }
1056 
1057  /*
1058  * Check if function can match by using parameter defaults.
1059  */
1060  if (pronargs > nargs && expand_defaults)
1061  {
1062  /* Ignore if not enough default expressions */
1063  if (nargs + procform->pronargdefaults < pronargs)
1064  continue;
1065  use_defaults = true;
1066  any_special = true;
1067  }
1068  else
1069  use_defaults = false;
1070 
1071  /* Ignore if it doesn't match requested argument count */
1072  if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
1073  continue;
1074  }
1075 
1076  /*
1077  * We must compute the effective argument list so that we can easily
1078  * compare it to earlier results. We waste a palloc cycle if it gets
1079  * masked by an earlier result, but really that's a pretty infrequent
1080  * case so it's not worth worrying about.
1081  */
1082  effective_nargs = Max(pronargs, nargs);
1083  newResult = (FuncCandidateList)
1085  effective_nargs * sizeof(Oid));
1086  newResult->pathpos = pathpos;
1087  newResult->oid = HeapTupleGetOid(proctup);
1088  newResult->nargs = effective_nargs;
1089  newResult->argnumbers = argnumbers;
1090  if (argnumbers)
1091  {
1092  /* Re-order the argument types into call's logical order */
1093  Oid *proargtypes = procform->proargtypes.values;
1094  int i;
1095 
1096  for (i = 0; i < pronargs; i++)
1097  newResult->args[i] = proargtypes[argnumbers[i]];
1098  }
1099  else
1100  {
1101  /* Simple positional case, just copy proargtypes as-is */
1102  memcpy(newResult->args, procform->proargtypes.values,
1103  pronargs * sizeof(Oid));
1104  }
1105  if (variadic)
1106  {
1107  int i;
1108 
1109  newResult->nvargs = effective_nargs - pronargs + 1;
1110  /* Expand variadic argument into N copies of element type */
1111  for (i = pronargs - 1; i < effective_nargs; i++)
1112  newResult->args[i] = va_elem_type;
1113  }
1114  else
1115  newResult->nvargs = 0;
1116  newResult->ndargs = use_defaults ? pronargs - nargs : 0;
1117 
1118  /*
1119  * Does it have the same arguments as something we already accepted?
1120  * If so, decide what to do to avoid returning duplicate argument
1121  * lists. We can skip this check for the single-namespace case if no
1122  * special (named, variadic or defaults) match has been made, since
1123  * then the unique index on pg_proc guarantees all the matches have
1124  * different argument lists.
1125  */
1126  if (resultList != NULL &&
1127  (any_special || !OidIsValid(namespaceId)))
1128  {
1129  /*
1130  * If we have an ordered list from SearchSysCacheList (the normal
1131  * case), then any conflicting proc must immediately adjoin this
1132  * one in the list, so we only need to look at the newest result
1133  * item. If we have an unordered list, we have to scan the whole
1134  * result list. Also, if either the current candidate or any
1135  * previous candidate is a special match, we can't assume that
1136  * conflicts are adjacent.
1137  *
1138  * We ignore defaulted arguments in deciding what is a match.
1139  */
1140  FuncCandidateList prevResult;
1141 
1142  if (catlist->ordered && !any_special)
1143  {
1144  /* ndargs must be 0 if !any_special */
1145  if (effective_nargs == resultList->nargs &&
1146  memcmp(newResult->args,
1147  resultList->args,
1148  effective_nargs * sizeof(Oid)) == 0)
1149  prevResult = resultList;
1150  else
1151  prevResult = NULL;
1152  }
1153  else
1154  {
1155  int cmp_nargs = newResult->nargs - newResult->ndargs;
1156 
1157  for (prevResult = resultList;
1158  prevResult;
1159  prevResult = prevResult->next)
1160  {
1161  if (cmp_nargs == prevResult->nargs - prevResult->ndargs &&
1162  memcmp(newResult->args,
1163  prevResult->args,
1164  cmp_nargs * sizeof(Oid)) == 0)
1165  break;
1166  }
1167  }
1168 
1169  if (prevResult)
1170  {
1171  /*
1172  * We have a match with a previous result. Decide which one
1173  * to keep, or mark it ambiguous if we can't decide. The
1174  * logic here is preference > 0 means prefer the old result,
1175  * preference < 0 means prefer the new, preference = 0 means
1176  * ambiguous.
1177  */
1178  int preference;
1179 
1180  if (pathpos != prevResult->pathpos)
1181  {
1182  /*
1183  * Prefer the one that's earlier in the search path.
1184  */
1185  preference = pathpos - prevResult->pathpos;
1186  }
1187  else if (variadic && prevResult->nvargs == 0)
1188  {
1189  /*
1190  * With variadic functions we could have, for example,
1191  * both foo(numeric) and foo(variadic numeric[]) in the
1192  * same namespace; if so we prefer the non-variadic match
1193  * on efficiency grounds.
1194  */
1195  preference = 1;
1196  }
1197  else if (!variadic && prevResult->nvargs > 0)
1198  {
1199  preference = -1;
1200  }
1201  else
1202  {
1203  /*----------
1204  * We can't decide. This can happen with, for example,
1205  * both foo(numeric, variadic numeric[]) and
1206  * foo(variadic numeric[]) in the same namespace, or
1207  * both foo(int) and foo (int, int default something)
1208  * in the same namespace, or both foo(a int, b text)
1209  * and foo(b text, a int) in the same namespace.
1210  *----------
1211  */
1212  preference = 0;
1213  }
1214 
1215  if (preference > 0)
1216  {
1217  /* keep previous result */
1218  pfree(newResult);
1219  continue;
1220  }
1221  else if (preference < 0)
1222  {
1223  /* remove previous result from the list */
1224  if (prevResult == resultList)
1225  resultList = prevResult->next;
1226  else
1227  {
1228  FuncCandidateList prevPrevResult;
1229 
1230  for (prevPrevResult = resultList;
1231  prevPrevResult;
1232  prevPrevResult = prevPrevResult->next)
1233  {
1234  if (prevResult == prevPrevResult->next)
1235  {
1236  prevPrevResult->next = prevResult->next;
1237  break;
1238  }
1239  }
1240  Assert(prevPrevResult); /* assert we found it */
1241  }
1242  pfree(prevResult);
1243  /* fall through to add newResult to list */
1244  }
1245  else
1246  {
1247  /* mark old result as ambiguous, discard new */
1248  prevResult->oid = InvalidOid;
1249  pfree(newResult);
1250  continue;
1251  }
1252  }
1253  }
1254 
1255  /*
1256  * Okay to add it to result list
1257  */
1258  newResult->next = resultList;
1259  resultList = newResult;
1260  }
1261 
1262  ReleaseSysCacheList(catlist);
1263 
1264  return resultList;
1265 }
1266 
1267 /*
1268  * MatchNamedCall
1269  * Given a pg_proc heap tuple and a call's list of argument names,
1270  * check whether the function could match the call.
1271  *
1272  * The call could match if all supplied argument names are accepted by
1273  * the function, in positions after the last positional argument, and there
1274  * are defaults for all unsupplied arguments.
1275  *
1276  * The number of positional arguments is nargs - list_length(argnames).
1277  * Note caller has already done basic checks on argument count.
1278  *
1279  * On match, return true and fill *argnumbers with a palloc'd array showing
1280  * the mapping from call argument positions to actual function argument
1281  * numbers. Defaulted arguments are included in this map, at positions
1282  * after the last supplied argument.
1283  */
1284 static bool
1285 MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
1286  int **argnumbers)
1287 {
1288  Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
1289  int pronargs = procform->pronargs;
1290  int numposargs = nargs - list_length(argnames);
1291  int pronallargs;
1292  Oid *p_argtypes;
1293  char **p_argnames;
1294  char *p_argmodes;
1295  bool arggiven[FUNC_MAX_ARGS];
1296  bool isnull;
1297  int ap; /* call args position */
1298  int pp; /* proargs position */
1299  ListCell *lc;
1300 
1301  Assert(argnames != NIL);
1302  Assert(numposargs >= 0);
1303  Assert(nargs <= pronargs);
1304 
1305  /* Ignore this function if its proargnames is null */
1306  (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proargnames,
1307  &isnull);
1308  if (isnull)
1309  return false;
1310 
1311  /* OK, let's extract the argument names and types */
1312  pronallargs = get_func_arg_info(proctup,
1313  &p_argtypes, &p_argnames, &p_argmodes);
1314  Assert(p_argnames != NULL);
1315 
1316  /* initialize state for matching */
1317  *argnumbers = (int *) palloc(pronargs * sizeof(int));
1318  memset(arggiven, false, pronargs * sizeof(bool));
1319 
1320  /* there are numposargs positional args before the named args */
1321  for (ap = 0; ap < numposargs; ap++)
1322  {
1323  (*argnumbers)[ap] = ap;
1324  arggiven[ap] = true;
1325  }
1326 
1327  /* now examine the named args */
1328  foreach(lc, argnames)
1329  {
1330  char *argname = (char *) lfirst(lc);
1331  bool found;
1332  int i;
1333 
1334  pp = 0;
1335  found = false;
1336  for (i = 0; i < pronallargs; i++)
1337  {
1338  /* consider only input parameters */
1339  if (p_argmodes &&
1340  (p_argmodes[i] != FUNC_PARAM_IN &&
1341  p_argmodes[i] != FUNC_PARAM_INOUT &&
1342  p_argmodes[i] != FUNC_PARAM_VARIADIC))
1343  continue;
1344  if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
1345  {
1346  /* fail if argname matches a positional argument */
1347  if (arggiven[pp])
1348  return false;
1349  arggiven[pp] = true;
1350  (*argnumbers)[ap] = pp;
1351  found = true;
1352  break;
1353  }
1354  /* increase pp only for input parameters */
1355  pp++;
1356  }
1357  /* if name isn't in proargnames, fail */
1358  if (!found)
1359  return false;
1360  ap++;
1361  }
1362 
1363  Assert(ap == nargs); /* processed all actual parameters */
1364 
1365  /* Check for default arguments */
1366  if (nargs < pronargs)
1367  {
1368  int first_arg_with_default = pronargs - procform->pronargdefaults;
1369 
1370  for (pp = numposargs; pp < pronargs; pp++)
1371  {
1372  if (arggiven[pp])
1373  continue;
1374  /* fail if arg not given and no default available */
1375  if (pp < first_arg_with_default)
1376  return false;
1377  (*argnumbers)[ap++] = pp;
1378  }
1379  }
1380 
1381  Assert(ap == pronargs); /* processed all function parameters */
1382 
1383  return true;
1384 }
1385 
1386 /*
1387  * FunctionIsVisible
1388  * Determine whether a function (identified by OID) is visible in the
1389  * current search path. Visible means "would be found by searching
1390  * for the unqualified function name with exact argument matches".
1391  */
1392 bool
1394 {
1395  HeapTuple proctup;
1396  Form_pg_proc procform;
1397  Oid pronamespace;
1398  bool visible;
1399 
1400  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1401  if (!HeapTupleIsValid(proctup))
1402  elog(ERROR, "cache lookup failed for function %u", funcid);
1403  procform = (Form_pg_proc) GETSTRUCT(proctup);
1404 
1406 
1407  /*
1408  * Quick check: if it ain't in the path at all, it ain't visible. Items in
1409  * the system namespace are surely in the path and so we needn't even do
1410  * list_member_oid() for them.
1411  */
1412  pronamespace = procform->pronamespace;
1413  if (pronamespace != PG_CATALOG_NAMESPACE &&
1414  !list_member_oid(activeSearchPath, pronamespace))
1415  visible = false;
1416  else
1417  {
1418  /*
1419  * If it is in the path, it might still not be visible; it could be
1420  * hidden by another proc of the same name and arguments earlier in
1421  * the path. So we must do a slow check to see if this is the same
1422  * proc that would be found by FuncnameGetCandidates.
1423  */
1424  char *proname = NameStr(procform->proname);
1425  int nargs = procform->pronargs;
1426  FuncCandidateList clist;
1427 
1428  visible = false;
1429 
1430  clist = FuncnameGetCandidates(list_make1(makeString(proname)),
1431  nargs, NIL, false, false, false);
1432 
1433  for (; clist; clist = clist->next)
1434  {
1435  if (memcmp(clist->args, procform->proargtypes.values,
1436  nargs * sizeof(Oid)) == 0)
1437  {
1438  /* Found the expected entry; is it the right proc? */
1439  visible = (clist->oid == funcid);
1440  break;
1441  }
1442  }
1443  }
1444 
1445  ReleaseSysCache(proctup);
1446 
1447  return visible;
1448 }
1449 
1450 
1451 /*
1452  * OpernameGetOprid
1453  * Given a possibly-qualified operator name and exact input datatypes,
1454  * look up the operator. Returns InvalidOid if not found.
1455  *
1456  * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
1457  * a postfix op.
1458  *
1459  * If the operator name is not schema-qualified, it is sought in the current
1460  * namespace search path. If the name is schema-qualified and the given
1461  * schema does not exist, InvalidOid is returned.
1462  */
1463 Oid
1464 OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
1465 {
1466  char *schemaname;
1467  char *opername;
1468  CatCList *catlist;
1469  ListCell *l;
1470 
1471  /* deconstruct the name list */
1472  DeconstructQualifiedName(names, &schemaname, &opername);
1473 
1474  if (schemaname)
1475  {
1476  /* search only in exact schema given */
1477  Oid namespaceId;
1478 
1479  namespaceId = LookupExplicitNamespace(schemaname, true);
1480  if (OidIsValid(namespaceId))
1481  {
1482  HeapTuple opertup;
1483 
1484  opertup = SearchSysCache4(OPERNAMENSP,
1485  CStringGetDatum(opername),
1486  ObjectIdGetDatum(oprleft),
1487  ObjectIdGetDatum(oprright),
1488  ObjectIdGetDatum(namespaceId));
1489  if (HeapTupleIsValid(opertup))
1490  {
1491  Oid result = HeapTupleGetOid(opertup);
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 = HeapTupleGetOid(opertup);
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 = HeapTupleGetOid(opertup);
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 = HeapTupleGetOid(opertup);
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,
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 
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) */
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 = HeapTupleGetOid(colltup);
1973  else
1974  collid = InvalidOid;
1975  }
1976  else
1977  {
1978  collid = HeapTupleGetOid(colltup);
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,
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,
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,
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
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 
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 failOK, 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,
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,
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
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 
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
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 
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 if first time through */
2926  return myTempNamespace;
2927  }
2928 
2929  namespaceId = get_namespace_oid(nspname, false);
2930 
2931  aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
2932  if (aclresult != ACLCHECK_OK)
2933  aclcheck_error(aclresult, OBJECT_SCHEMA,
2934  nspname);
2935 
2936  return namespaceId;
2937 }
2938 
2939 /*
2940  * Common checks on switching namespaces.
2941  *
2942  * We complain if either the old or new namespaces is a temporary schema
2943  * (or temporary toast schema), or if either the old or new namespaces is the
2944  * TOAST schema.
2945  */
2946 void
2947 CheckSetNamespace(Oid oldNspOid, Oid nspOid)
2948 {
2949  /* disallow renaming into or out of temp schemas */
2950  if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
2951  ereport(ERROR,
2952  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2953  errmsg("cannot move objects into or out of temporary schemas")));
2954 
2955  /* same for TOAST schema */
2956  if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
2957  ereport(ERROR,
2958  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2959  errmsg("cannot move objects into or out of TOAST schema")));
2960 }
2961 
2962 /*
2963  * QualifiedNameGetCreationNamespace
2964  * Given a possibly-qualified name for an object (in List-of-Values
2965  * format), determine what namespace the object should be created in.
2966  * Also extract and return the object name (last component of list).
2967  *
2968  * Note: this does not apply any permissions check. Callers must check
2969  * for CREATE rights on the selected namespace when appropriate.
2970  *
2971  * Note: calling this may result in a CommandCounterIncrement operation,
2972  * if we have to create or clean out the temp namespace.
2973  */
2974 Oid
2975 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
2976 {
2977  char *schemaname;
2978  Oid namespaceId;
2979 
2980  /* deconstruct the name list */
2981  DeconstructQualifiedName(names, &schemaname, objname_p);
2982 
2983  if (schemaname)
2984  {
2985  /* check for pg_temp alias */
2986  if (strcmp(schemaname, "pg_temp") == 0)
2987  {
2988  /* Initialize temp namespace if first time through */
2991  return myTempNamespace;
2992  }
2993  /* use exact schema given */
2994  namespaceId = get_namespace_oid(schemaname, false);
2995  /* we do not check for USAGE rights here! */
2996  }
2997  else
2998  {
2999  /* use the default creation namespace */
3002  {
3003  /* Need to initialize temp namespace */
3005  return myTempNamespace;
3006  }
3007  namespaceId = activeCreationNamespace;
3008  if (!OidIsValid(namespaceId))
3009  ereport(ERROR,
3010  (errcode(ERRCODE_UNDEFINED_SCHEMA),
3011  errmsg("no schema has been selected to create in")));
3012  }
3013 
3014  return namespaceId;
3015 }
3016 
3017 /*
3018  * get_namespace_oid - given a namespace name, look up the OID
3019  *
3020  * If missing_ok is false, throw an error if namespace name not found. If
3021  * true, just return InvalidOid.
3022  */
3023 Oid
3024 get_namespace_oid(const char *nspname, bool missing_ok)
3025 {
3026  Oid oid;
3027 
3029  if (!OidIsValid(oid) && !missing_ok)
3030  ereport(ERROR,
3031  (errcode(ERRCODE_UNDEFINED_SCHEMA),
3032  errmsg("schema \"%s\" does not exist", nspname)));
3033 
3034  return oid;
3035 }
3036 
3037 /*
3038  * makeRangeVarFromNameList
3039  * Utility routine to convert a qualified-name list into RangeVar form.
3040  */
3041 RangeVar *
3043 {
3044  RangeVar *rel = makeRangeVar(NULL, NULL, -1);
3045 
3046  switch (list_length(names))
3047  {
3048  case 1:
3049  rel->relname = strVal(linitial(names));
3050  break;
3051  case 2:
3052  rel->schemaname = strVal(linitial(names));
3053  rel->relname = strVal(lsecond(names));
3054  break;
3055  case 3:
3056  rel->catalogname = strVal(linitial(names));
3057  rel->schemaname = strVal(lsecond(names));
3058  rel->relname = strVal(lthird(names));
3059  break;
3060  default:
3061  ereport(ERROR,
3062  (errcode(ERRCODE_SYNTAX_ERROR),
3063  errmsg("improper relation name (too many dotted names): %s",
3064  NameListToString(names))));
3065  break;
3066  }
3067 
3068  return rel;
3069 }
3070 
3071 /*
3072  * NameListToString
3073  * Utility routine to convert a qualified-name list into a string.
3074  *
3075  * This is used primarily to form error messages, and so we do not quote
3076  * the list elements, for the sake of legibility.
3077  *
3078  * In most scenarios the list elements should always be Value strings,
3079  * but we also allow A_Star for the convenience of ColumnRef processing.
3080  */
3081 char *
3083 {
3085  ListCell *l;
3086 
3087  initStringInfo(&string);
3088 
3089  foreach(l, names)
3090  {
3091  Node *name = (Node *) lfirst(l);
3092 
3093  if (l != list_head(names))
3094  appendStringInfoChar(&string, '.');
3095 
3096  if (IsA(name, String))
3097  appendStringInfoString(&string, strVal(name));
3098  else if (IsA(name, A_Star))
3099  appendStringInfoChar(&string, '*');
3100  else
3101  elog(ERROR, "unexpected node type in name list: %d",
3102  (int) nodeTag(name));
3103  }
3104 
3105  return string.data;
3106 }
3107 
3108 /*
3109  * NameListToQuotedString
3110  * Utility routine to convert a qualified-name list into a string.
3111  *
3112  * Same as above except that names will be double-quoted where necessary,
3113  * so the string could be re-parsed (eg, by textToQualifiedNameList).
3114  */
3115 char *
3117 {
3119  ListCell *l;
3120 
3121  initStringInfo(&string);
3122 
3123  foreach(l, names)
3124  {
3125  if (l != list_head(names))
3126  appendStringInfoChar(&string, '.');
3128  }
3129 
3130  return string.data;
3131 }
3132 
3133 /*
3134  * isTempNamespace - is the given namespace my temporary-table namespace?
3135  */
3136 bool
3137 isTempNamespace(Oid namespaceId)
3138 {
3139  if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
3140  return true;
3141  return false;
3142 }
3143 
3144 /*
3145  * isTempToastNamespace - is the given namespace my temporary-toast-table
3146  * namespace?
3147  */
3148 bool
3150 {
3151  if (OidIsValid(myTempToastNamespace) && myTempToastNamespace == namespaceId)
3152  return true;
3153  return false;
3154 }
3155 
3156 /*
3157  * isTempOrTempToastNamespace - is the given namespace my temporary-table
3158  * namespace or my temporary-toast-table namespace?
3159  */
3160 bool
3162 {
3163  if (OidIsValid(myTempNamespace) &&
3164  (myTempNamespace == namespaceId || myTempToastNamespace == namespaceId))
3165  return true;
3166  return false;
3167 }
3168 
3169 /*
3170  * isAnyTempNamespace - is the given namespace a temporary-table namespace
3171  * (either my own, or another backend's)? Temporary-toast-table namespaces
3172  * are included, too.
3173  */
3174 bool
3176 {
3177  bool result;
3178  char *nspname;
3179 
3180  /* True if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
3181  nspname = get_namespace_name(namespaceId);
3182  if (!nspname)
3183  return false; /* no such namespace? */
3184  result = (strncmp(nspname, "pg_temp_", 8) == 0) ||
3185  (strncmp(nspname, "pg_toast_temp_", 14) == 0);
3186  pfree(nspname);
3187  return result;
3188 }
3189 
3190 /*
3191  * isOtherTempNamespace - is the given namespace some other backend's
3192  * temporary-table namespace (including temporary-toast-table namespaces)?
3193  *
3194  * Note: for most purposes in the C code, this function is obsolete. Use
3195  * RELATION_IS_OTHER_TEMP() instead to detect non-local temp relations.
3196  */
3197 bool
3199 {
3200  /* If it's my own temp namespace, say "false" */
3201  if (isTempOrTempToastNamespace(namespaceId))
3202  return false;
3203  /* Else, if it's any temp namespace, say "true" */
3204  return isAnyTempNamespace(namespaceId);
3205 }
3206 
3207 /*
3208  * GetTempNamespaceBackendId - if the given namespace is a temporary-table
3209  * namespace (either my own, or another backend's), return the BackendId
3210  * that owns it. Temporary-toast-table namespaces are included, too.
3211  * If it isn't a temp namespace, return InvalidBackendId.
3212  */
3213 int
3215 {
3216  int result;
3217  char *nspname;
3218 
3219  /* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
3220  nspname = get_namespace_name(namespaceId);
3221  if (!nspname)
3222  return InvalidBackendId; /* no such namespace? */
3223  if (strncmp(nspname, "pg_temp_", 8) == 0)
3224  result = atoi(nspname + 8);
3225  else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
3226  result = atoi(nspname + 14);
3227  else
3228  result = InvalidBackendId;
3229  pfree(nspname);
3230  return result;
3231 }
3232 
3233 /*
3234  * GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
3235  * which must already be assigned. (This is only used when creating a toast
3236  * table for a temp table, so we must have already done InitTempTableNamespace)
3237  */
3238 Oid
3240 {
3242  return myTempToastNamespace;
3243 }
3244 
3245 
3246 /*
3247  * GetTempNamespaceState - fetch status of session's temporary namespace
3248  *
3249  * This is used for conveying state to a parallel worker, and is not meant
3250  * for general-purpose access.
3251  */
3252 void
3253 GetTempNamespaceState(Oid *tempNamespaceId, Oid *tempToastNamespaceId)
3254 {
3255  /* Return namespace OIDs, or 0 if session has not created temp namespace */
3256  *tempNamespaceId = myTempNamespace;
3257  *tempToastNamespaceId = myTempToastNamespace;
3258 }
3259 
3260 /*
3261  * SetTempNamespaceState - set status of session's temporary namespace
3262  *
3263  * This is used for conveying state to a parallel worker, and is not meant for
3264  * general-purpose access. By transferring these namespace OIDs to workers,
3265  * we ensure they will have the same notion of the search path as their leader
3266  * does.
3267  */
3268 void
3269 SetTempNamespaceState(Oid tempNamespaceId, Oid tempToastNamespaceId)
3270 {
3271  /* Worker should not have created its own namespaces ... */
3275 
3276  /* Assign same namespace OIDs that leader has */
3277  myTempNamespace = tempNamespaceId;
3278  myTempToastNamespace = tempToastNamespaceId;
3279 
3280  /*
3281  * It's fine to leave myTempNamespaceSubID == InvalidSubTransactionId.
3282  * Even if the namespace is new so far as the leader is concerned, it's
3283  * not new to the worker, and we certainly wouldn't want the worker trying
3284  * to destroy it.
3285  */
3286 
3287  baseSearchPathValid = false; /* may need to rebuild list */
3288 }
3289 
3290 
3291 /*
3292  * GetOverrideSearchPath - fetch current search path definition in form
3293  * used by PushOverrideSearchPath.
3294  *
3295  * The result structure is allocated in the specified memory context
3296  * (which might or might not be equal to CurrentMemoryContext); but any
3297  * junk created by revalidation calculations will be in CurrentMemoryContext.
3298  */
3301 {
3302  OverrideSearchPath *result;
3303  List *schemas;
3304  MemoryContext oldcxt;
3305 
3307 
3308  oldcxt = MemoryContextSwitchTo(context);
3309 
3310  result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
3311  schemas = list_copy(activeSearchPath);
3312  while (schemas && linitial_oid(schemas) != activeCreationNamespace)
3313  {
3314  if (linitial_oid(schemas) == myTempNamespace)
3315  result->addTemp = true;
3316  else
3317  {
3318  Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
3319  result->addCatalog = true;
3320  }
3321  schemas = list_delete_first(schemas);
3322  }
3323  result->schemas = schemas;
3324 
3325  MemoryContextSwitchTo(oldcxt);
3326 
3327  return result;
3328 }
3329 
3330 /*
3331  * CopyOverrideSearchPath - copy the specified OverrideSearchPath.
3332  *
3333  * The result structure is allocated in CurrentMemoryContext.
3334  */
3337 {
3338  OverrideSearchPath *result;
3339 
3340  result = (OverrideSearchPath *) palloc(sizeof(OverrideSearchPath));
3341  result->schemas = list_copy(path->schemas);
3342  result->addCatalog = path->addCatalog;
3343  result->addTemp = path->addTemp;
3344 
3345  return result;
3346 }
3347 
3348 /*
3349  * OverrideSearchPathMatchesCurrent - does path match current setting?
3350  */
3351 bool
3353 {
3354  ListCell *lc,
3355  *lcp;
3356 
3358 
3359  /* We scan down the activeSearchPath to see if it matches the input. */
3360  lc = list_head(activeSearchPath);
3361 
3362  /* If path->addTemp, first item should be my temp namespace. */
3363  if (path->addTemp)
3364  {
3365  if (lc && lfirst_oid(lc) == myTempNamespace)
3366  lc = lnext(lc);
3367  else
3368  return false;
3369  }
3370  /* If path->addCatalog, next item should be pg_catalog. */
3371  if (path->addCatalog)
3372  {
3373  if (lc && lfirst_oid(lc) == PG_CATALOG_NAMESPACE)
3374  lc = lnext(lc);
3375  else
3376  return false;
3377  }
3378  /* We should now be looking at the activeCreationNamespace. */
3379  if (activeCreationNamespace != (lc ? lfirst_oid(lc) : InvalidOid))
3380  return false;
3381  /* The remainder of activeSearchPath should match path->schemas. */
3382  foreach(lcp, path->schemas)
3383  {
3384  if (lc && lfirst_oid(lc) == lfirst_oid(lcp))
3385  lc = lnext(lc);
3386  else
3387  return false;
3388  }
3389  if (lc)
3390  return false;
3391  return true;
3392 }
3393 
3394 /*
3395  * PushOverrideSearchPath - temporarily override the search path
3396  *
3397  * We allow nested overrides, hence the push/pop terminology. The GUC
3398  * search_path variable is ignored while an override is active.
3399  *
3400  * It's possible that newpath->useTemp is set but there is no longer any
3401  * active temp namespace, if the path was saved during a transaction that
3402  * created a temp namespace and was later rolled back. In that case we just
3403  * ignore useTemp. A plausible alternative would be to create a new temp
3404  * namespace, but for existing callers that's not necessary because an empty
3405  * temp namespace wouldn't affect their results anyway.
3406  *
3407  * It's also worth noting that other schemas listed in newpath might not
3408  * exist anymore either. We don't worry about this because OIDs that match
3409  * no existing namespace will simply not produce any hits during searches.
3410  */
3411 void
3413 {
3414  OverrideStackEntry *entry;
3415  List *oidlist;
3416  Oid firstNS;
3417  MemoryContext oldcxt;
3418 
3419  /*
3420  * Copy the list for safekeeping, and insert implicitly-searched
3421  * namespaces as needed. This code should track recomputeNamespacePath.
3422  */
3424 
3425  oidlist = list_copy(newpath->schemas);
3426 
3427  /*
3428  * Remember the first member of the explicit list.
3429  */
3430  if (oidlist == NIL)
3431  firstNS = InvalidOid;
3432  else
3433  firstNS = linitial_oid(oidlist);
3434 
3435  /*
3436  * Add any implicitly-searched namespaces to the list. Note these go on
3437  * the front, not the back; also notice that we do not check USAGE
3438  * permissions for these.
3439  */
3440  if (newpath->addCatalog)
3441  oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
3442 
3443  if (newpath->addTemp && OidIsValid(myTempNamespace))
3444  oidlist = lcons_oid(myTempNamespace, oidlist);
3445 
3446  /*
3447  * Build the new stack entry, then insert it at the head of the list.
3448  */
3449  entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
3450  entry->searchPath = oidlist;
3451  entry->creationNamespace = firstNS;
3453 
3454  overrideStack = lcons(entry, overrideStack);
3455 
3456  /* And make it active. */
3457  activeSearchPath = entry->searchPath;
3459  activeTempCreationPending = false; /* XXX is this OK? */
3460 
3461  MemoryContextSwitchTo(oldcxt);
3462 }
3463 
3464 /*
3465  * PopOverrideSearchPath - undo a previous PushOverrideSearchPath
3466  *
3467  * Any push during a (sub)transaction will be popped automatically at abort.
3468  * But it's caller error if a push isn't popped in normal control flow.
3469  */
3470 void
3472 {
3473  OverrideStackEntry *entry;
3474 
3475  /* Sanity checks. */
3476  if (overrideStack == NIL)
3477  elog(ERROR, "bogus PopOverrideSearchPath call");
3478  entry = (OverrideStackEntry *) linitial(overrideStack);
3479  if (entry->nestLevel != GetCurrentTransactionNestLevel())
3480  elog(ERROR, "bogus PopOverrideSearchPath call");
3481 
3482  /* Pop the stack and free storage. */
3483  overrideStack = list_delete_first(overrideStack);
3484  list_free(entry->searchPath);
3485  pfree(entry);
3486 
3487  /* Activate the next level down. */
3488  if (overrideStack)
3489  {
3490  entry = (OverrideStackEntry *) linitial(overrideStack);
3491  activeSearchPath = entry->searchPath;
3493  activeTempCreationPending = false; /* XXX is this OK? */
3494  }
3495  else
3496  {
3497  /* If not baseSearchPathValid, this is useless but harmless */
3498  activeSearchPath = baseSearchPath;
3501  }
3502 }
3503 
3504 
3505 /*
3506  * get_collation_oid - find a collation by possibly qualified name
3507  *
3508  * Note that this will only find collations that work with the current
3509  * database's encoding.
3510  */
3511 Oid
3512 get_collation_oid(List *name, bool missing_ok)
3513 {
3514  char *schemaname;
3515  char *collation_name;
3516  int32 dbencoding = GetDatabaseEncoding();
3517  Oid namespaceId;
3518  Oid colloid;
3519  ListCell *l;
3520 
3521  /* deconstruct the name list */
3522  DeconstructQualifiedName(name, &schemaname, &collation_name);
3523 
3524  if (schemaname)
3525  {
3526  /* use exact schema given */
3527  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3528  if (missing_ok && !OidIsValid(namespaceId))
3529  return InvalidOid;
3530 
3531  colloid = lookup_collation(collation_name, namespaceId, dbencoding);
3532  if (OidIsValid(colloid))
3533  return colloid;
3534  }
3535  else
3536  {
3537  /* search for it in search path */
3539 
3540  foreach(l, activeSearchPath)
3541  {
3542  namespaceId = lfirst_oid(l);
3543 
3544  if (namespaceId == myTempNamespace)
3545  continue; /* do not look in temp namespace */
3546 
3547  colloid = lookup_collation(collation_name, namespaceId, dbencoding);
3548  if (OidIsValid(colloid))
3549  return colloid;
3550  }
3551  }
3552 
3553  /* Not found in path */
3554  if (!missing_ok)
3555  ereport(ERROR,
3556  (errcode(ERRCODE_UNDEFINED_OBJECT),
3557  errmsg("collation \"%s\" for encoding \"%s\" does not exist",
3559  return InvalidOid;
3560 }
3561 
3562 /*
3563  * get_conversion_oid - find a conversion by possibly qualified name
3564  */
3565 Oid
3566 get_conversion_oid(List *name, bool missing_ok)
3567 {
3568  char *schemaname;
3569  char *conversion_name;
3570  Oid namespaceId;
3571  Oid conoid = InvalidOid;
3572  ListCell *l;
3573 
3574  /* deconstruct the name list */
3575  DeconstructQualifiedName(name, &schemaname, &conversion_name);
3576 
3577  if (schemaname)
3578  {
3579  /* use exact schema given */
3580  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3581  if (missing_ok && !OidIsValid(namespaceId))
3582  conoid = InvalidOid;
3583  else
3584  conoid = GetSysCacheOid2(CONNAMENSP,
3585  PointerGetDatum(conversion_name),
3586  ObjectIdGetDatum(namespaceId));
3587  }
3588  else
3589  {
3590  /* search for it in search path */
3592 
3593  foreach(l, activeSearchPath)
3594  {
3595  namespaceId = lfirst_oid(l);
3596 
3597  if (namespaceId == myTempNamespace)
3598  continue; /* do not look in temp namespace */
3599 
3600  conoid = GetSysCacheOid2(CONNAMENSP,
3601  PointerGetDatum(conversion_name),
3602  ObjectIdGetDatum(namespaceId));
3603  if (OidIsValid(conoid))
3604  return conoid;
3605  }
3606  }
3607 
3608  /* Not found in path */
3609  if (!OidIsValid(conoid) && !missing_ok)
3610  ereport(ERROR,
3611  (errcode(ERRCODE_UNDEFINED_OBJECT),
3612  errmsg("conversion \"%s\" does not exist",
3613  NameListToString(name))));
3614  return conoid;
3615 }
3616 
3617 /*
3618  * FindDefaultConversionProc - find default encoding conversion proc
3619  */
3620 Oid
3621 FindDefaultConversionProc(int32 for_encoding, int32 to_encoding)
3622 {
3623  Oid proc;
3624  ListCell *l;
3625 
3627 
3628  foreach(l, activeSearchPath)
3629  {
3630  Oid namespaceId = lfirst_oid(l);
3631 
3632  if (namespaceId == myTempNamespace)
3633  continue; /* do not look in temp namespace */
3634 
3635  proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
3636  if (OidIsValid(proc))
3637  return proc;
3638  }
3639 
3640  /* Not found in path */
3641  return InvalidOid;
3642 }
3643 
3644 /*
3645  * recomputeNamespacePath - recompute path derived variables if needed.
3646  */
3647 static void
3649 {
3650  Oid roleid = GetUserId();
3651  char *rawname;
3652  List *namelist;
3653  List *oidlist;
3654  List *newpath;
3655  ListCell *l;
3656  bool temp_missing;
3657  Oid firstNS;
3658  MemoryContext oldcxt;
3659 
3660  /* Do nothing if an override search spec is active. */
3661  if (overrideStack)
3662  return;
3663 
3664  /* Do nothing if path is already valid. */
3665  if (baseSearchPathValid && namespaceUser == roleid)
3666  return;
3667 
3668  /* Need a modifiable copy of namespace_search_path string */
3669  rawname = pstrdup(namespace_search_path);
3670 
3671  /* Parse string into list of identifiers */
3672  if (!SplitIdentifierString(rawname, ',', &namelist))
3673  {
3674  /* syntax error in name list */
3675  /* this should not happen if GUC checked check_search_path */
3676  elog(ERROR, "invalid list syntax");
3677  }
3678 
3679  /*
3680  * Convert the list of names to a list of OIDs. If any names are not
3681  * recognizable or we don't have read access, just leave them out of the
3682  * list. (We can't raise an error, since the search_path setting has
3683  * already been accepted.) Don't make duplicate entries, either.
3684  */
3685  oidlist = NIL;
3686  temp_missing = false;
3687  foreach(l, namelist)
3688  {
3689  char *curname = (char *) lfirst(l);
3690  Oid namespaceId;
3691 
3692  if (strcmp(curname, "$user") == 0)
3693  {
3694  /* $user --- substitute namespace matching user name, if any */
3695  HeapTuple tuple;
3696 
3697  tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
3698  if (HeapTupleIsValid(tuple))
3699  {
3700  char *rname;
3701 
3702  rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
3703  namespaceId = get_namespace_oid(rname, true);
3704  ReleaseSysCache(tuple);
3705  if (OidIsValid(namespaceId) &&
3706  !list_member_oid(oidlist, namespaceId) &&
3707  pg_namespace_aclcheck(namespaceId, roleid,
3708  ACL_USAGE) == ACLCHECK_OK &&
3709  InvokeNamespaceSearchHook(namespaceId, false))
3710  oidlist = lappend_oid(oidlist, namespaceId);
3711  }
3712  }
3713  else if (strcmp(curname, "pg_temp") == 0)
3714  {
3715  /* pg_temp --- substitute temp namespace, if any */
3717  {
3718  if (!list_member_oid(oidlist, myTempNamespace) &&
3720  oidlist = lappend_oid(oidlist, myTempNamespace);
3721  }
3722  else
3723  {
3724  /* If it ought to be the creation namespace, set flag */
3725  if (oidlist == NIL)
3726  temp_missing = true;
3727  }
3728  }
3729  else
3730  {
3731  /* normal namespace reference */
3732  namespaceId = get_namespace_oid(curname, true);
3733  if (OidIsValid(namespaceId) &&
3734  !list_member_oid(oidlist, namespaceId) &&
3735  pg_namespace_aclcheck(namespaceId, roleid,
3736  ACL_USAGE) == ACLCHECK_OK &&
3737  InvokeNamespaceSearchHook(namespaceId, false))
3738  oidlist = lappend_oid(oidlist, namespaceId);
3739  }
3740  }
3741 
3742  /*
3743  * Remember the first member of the explicit list. (Note: this is
3744  * nominally wrong if temp_missing, but we need it anyway to distinguish
3745  * explicit from implicit mention of pg_catalog.)
3746  */
3747  if (oidlist == NIL)
3748  firstNS = InvalidOid;
3749  else
3750  firstNS = linitial_oid(oidlist);
3751 
3752  /*
3753  * Add any implicitly-searched namespaces to the list. Note these go on
3754  * the front, not the back; also notice that we do not check USAGE
3755  * permissions for these.
3756  */
3757  if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
3758  oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
3759 
3760  if (OidIsValid(myTempNamespace) &&
3761  !list_member_oid(oidlist, myTempNamespace))
3762  oidlist = lcons_oid(myTempNamespace, oidlist);
3763 
3764  /*
3765  * Now that we've successfully built the new list of namespace OIDs, save
3766  * it in permanent storage.
3767  */
3769  newpath = list_copy(oidlist);
3770  MemoryContextSwitchTo(oldcxt);
3771 
3772  /* Now safe to assign to state variables. */
3773  list_free(baseSearchPath);
3774  baseSearchPath = newpath;
3775  baseCreationNamespace = firstNS;
3776  baseTempCreationPending = temp_missing;
3777 
3778  /* Mark the path valid. */
3779  baseSearchPathValid = true;
3780  namespaceUser = roleid;
3781 
3782  /* And make it active. */
3783  activeSearchPath = baseSearchPath;
3786 
3787  /* Clean up. */
3788  pfree(rawname);
3789  list_free(namelist);
3790  list_free(oidlist);
3791 }
3792 
3793 /*
3794  * InitTempTableNamespace
3795  * Initialize temp table namespace on first use in a particular backend
3796  */
3797 static void
3799 {
3800  char namespaceName[NAMEDATALEN];
3801  Oid namespaceId;
3802  Oid toastspaceId;
3803 
3805 
3806  /*
3807  * First, do permission check to see if we are authorized to make temp
3808  * tables. We use a nonstandard error message here since "databasename:
3809  * permission denied" might be a tad cryptic.
3810  *
3811  * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
3812  * that's necessary since current user ID could change during the session.
3813  * But there's no need to make the namespace in the first place until a
3814  * temp table creation request is made by someone with appropriate rights.
3815  */
3818  ereport(ERROR,
3819  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3820  errmsg("permission denied to create temporary tables in database \"%s\"",
3822 
3823  /*
3824  * Do not allow a Hot Standby session to make temp tables. Aside from
3825  * problems with modifying the system catalogs, there is a naming
3826  * conflict: pg_temp_N belongs to the session with BackendId N on the
3827  * master, not to a hot standby session with the same BackendId. We
3828  * should not be able to get here anyway due to XactReadOnly checks, but
3829  * let's just make real sure. Note that this also backstops various
3830  * operations that allow XactReadOnly transactions to modify temp tables;
3831  * they'd need RecoveryInProgress checks if not for this.
3832  */
3833  if (RecoveryInProgress())
3834  ereport(ERROR,
3835  (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
3836  errmsg("cannot create temporary tables during recovery")));
3837 
3838  /* Parallel workers can't create temporary tables, either. */
3839  if (IsParallelWorker())
3840  ereport(ERROR,
3841  (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
3842  errmsg("cannot create temporary tables during a parallel operation")));
3843 
3844  snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
3845 
3846  namespaceId = get_namespace_oid(namespaceName, true);
3847  if (!OidIsValid(namespaceId))
3848  {
3849  /*
3850  * First use of this temp namespace in this database; create it. The
3851  * temp namespaces are always owned by the superuser. We leave their
3852  * permissions at default --- i.e., no access except to superuser ---
3853  * to ensure that unprivileged users can't peek at other backends'
3854  * temp tables. This works because the places that access the temp
3855  * namespace for my own backend skip permissions checks on it.
3856  */
3857  namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
3858  true);
3859  /* Advance command counter to make namespace visible */
3861  }
3862  else
3863  {
3864  /*
3865  * If the namespace already exists, clean it out (in case the former
3866  * owner crashed without doing so).
3867  */
3868  RemoveTempRelations(namespaceId);
3869  }
3870 
3871  /*
3872  * If the corresponding toast-table namespace doesn't exist yet, create
3873  * it. (We assume there is no need to clean it out if it does exist, since
3874  * dropping a parent table should make its toast table go away.)
3875  */
3876  snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d",
3877  MyBackendId);
3878 
3879  toastspaceId = get_namespace_oid(namespaceName, true);
3880  if (!OidIsValid(toastspaceId))
3881  {
3882  toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
3883  true);
3884  /* Advance command counter to make namespace visible */
3886  }
3887 
3888  /*
3889  * Okay, we've prepared the temp namespace ... but it's not committed yet,
3890  * so all our work could be undone by transaction rollback. Set flag for
3891  * AtEOXact_Namespace to know what to do.
3892  */
3893  myTempNamespace = namespaceId;
3894  myTempToastNamespace = toastspaceId;
3895 
3896  /* It should not be done already. */
3899 
3900  baseSearchPathValid = false; /* need to rebuild list */
3901 }
3902 
3903 /*
3904  * End-of-transaction cleanup for namespaces.
3905  */
3906 void
3907 AtEOXact_Namespace(bool isCommit, bool parallel)
3908 {
3909  /*
3910  * If we abort the transaction in which a temp namespace was selected,
3911  * we'll have to do any creation or cleanout work over again. So, just
3912  * forget the namespace entirely until next time. On the other hand, if
3913  * we commit then register an exit callback to clean out the temp tables
3914  * at backend shutdown. (We only want to register the callback once per
3915  * session, so this is a good place to do it.)
3916  */
3917  if (myTempNamespaceSubID != InvalidSubTransactionId && !parallel)
3918  {
3919  if (isCommit)
3921  else
3922  {
3925  baseSearchPathValid = false; /* need to rebuild list */
3926  }
3928  }
3929 
3930  /*
3931  * Clean up if someone failed to do PopOverrideSearchPath
3932  */
3933  if (overrideStack)
3934  {
3935  if (isCommit)
3936  elog(WARNING, "leaked override search path");
3937  while (overrideStack)
3938  {
3939  OverrideStackEntry *entry;
3940 
3941  entry = (OverrideStackEntry *) linitial(overrideStack);
3942  overrideStack = list_delete_first(overrideStack);
3943  list_free(entry->searchPath);
3944  pfree(entry);
3945  }
3946  /* If not baseSearchPathValid, this is useless but harmless */
3947  activeSearchPath = baseSearchPath;
3950  }
3951 }
3952 
3953 /*
3954  * AtEOSubXact_Namespace
3955  *
3956  * At subtransaction commit, propagate the temp-namespace-creation
3957  * flag to the parent subtransaction.
3958  *
3959  * At subtransaction abort, forget the flag if we set it up.
3960  */
3961 void
3963  SubTransactionId parentSubid)
3964 {
3965  OverrideStackEntry *entry;
3966 
3967  if (myTempNamespaceSubID == mySubid)
3968  {
3969  if (isCommit)
3970  myTempNamespaceSubID = parentSubid;
3971  else
3972  {
3974  /* TEMP namespace creation failed, so reset state */
3977  baseSearchPathValid = false; /* need to rebuild list */
3978  }
3979  }
3980 
3981  /*
3982  * Clean up if someone failed to do PopOverrideSearchPath
3983  */
3984  while (overrideStack)
3985  {
3986  entry = (OverrideStackEntry *) linitial(overrideStack);
3988  break;
3989  if (isCommit)
3990  elog(WARNING, "leaked override search path");
3991  overrideStack = list_delete_first(overrideStack);
3992  list_free(entry->searchPath);
3993  pfree(entry);
3994  }
3995 
3996  /* Activate the next level down. */
3997  if (overrideStack)
3998  {
3999  entry = (OverrideStackEntry *) linitial(overrideStack);
4000  activeSearchPath = entry->searchPath;
4002  activeTempCreationPending = false; /* XXX is this OK? */
4003  }
4004  else
4005  {
4006  /* If not baseSearchPathValid, this is useless but harmless */
4007  activeSearchPath = baseSearchPath;
4010  }
4011 }
4012 
4013 /*
4014  * Remove all relations in the specified temp namespace.
4015  *
4016  * This is called at backend shutdown (if we made any temp relations).
4017  * It is also called when we begin using a pre-existing temp namespace,
4018  * in order to clean out any relations that might have been created by
4019  * a crashed backend.
4020  */
4021 static void
4022 RemoveTempRelations(Oid tempNamespaceId)
4023 {
4024  ObjectAddress object;
4025 
4026  /*
4027  * We want to get rid of everything in the target namespace, but not the
4028  * namespace itself (deleting it only to recreate it later would be a
4029  * waste of cycles). Hence, specify SKIP_ORIGINAL. It's also an INTERNAL
4030  * deletion, and we want to not drop any extensions that might happen to
4031  * own temp objects.
4032  */
4033  object.classId = NamespaceRelationId;
4034  object.objectId = tempNamespaceId;
4035  object.objectSubId = 0;
4036 
4037  performDeletion(&object, DROP_CASCADE,
4042 }
4043 
4044 /*
4045  * Callback to remove temp relations at backend exit.
4046  */
4047 static void
4049 {
4050  if (OidIsValid(myTempNamespace)) /* should always be true */
4051  {
4052  /* Need to ensure we have a usable transaction. */
4055 
4057 
4059  }
4060 }
4061 
4062 /*
4063  * Remove all temp tables from the temporary namespace.
4064  */
4065 void
4067 {
4070 }
4071 
4072 
4073 /*
4074  * Routines for handling the GUC variable 'search_path'.
4075  */
4076 
4077 /* check_hook: validate new search_path value */
4078 bool
4079 check_search_path(char **newval, void **extra, GucSource source)
4080 {
4081  char *rawname;
4082  List *namelist;
4083 
4084  /* Need a modifiable copy of string */
4085  rawname = pstrdup(*newval);
4086 
4087  /* Parse string into list of identifiers */
4088  if (!SplitIdentifierString(rawname, ',', &namelist))
4089  {
4090  /* syntax error in name list */
4091  GUC_check_errdetail("List syntax is invalid.");
4092  pfree(rawname);
4093  list_free(namelist);
4094  return false;
4095  }
4096 
4097  /*
4098  * We used to try to check that the named schemas exist, but there are
4099  * many valid use-cases for having search_path settings that include
4100  * schemas that don't exist; and often, we are not inside a transaction
4101  * here and so can't consult the system catalogs anyway. So now, the only
4102  * requirement is syntactic validity of the identifier list.
4103  */
4104 
4105  pfree(rawname);
4106  list_free(namelist);
4107 
4108  return true;
4109 }
4110 
4111 /* assign_hook: do extra actions as needed */
4112 void
4113 assign_search_path(const char *newval, void *extra)
4114 {
4115  /*
4116  * We mark the path as needing recomputation, but don't do anything until
4117  * it's needed. This avoids trying to do database access during GUC
4118  * initialization, or outside a transaction.
4119  */
4120  baseSearchPathValid = false;
4121 }
4122 
4123 /*
4124  * InitializeSearchPath: initialize module during InitPostgres.
4125  *
4126  * This is called after we are up enough to be able to do catalog lookups.
4127  */
4128 void
4130 {
4132  {
4133  /*
4134  * In bootstrap mode, the search path must be 'pg_catalog' so that
4135  * tables are created in the proper namespace; ignore the GUC setting.
4136  */
4137  MemoryContext oldcxt;
4138 
4140  baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
4141  MemoryContextSwitchTo(oldcxt);
4142  baseCreationNamespace = PG_CATALOG_NAMESPACE;
4143  baseTempCreationPending = false;
4144  baseSearchPathValid = true;
4146  activeSearchPath = baseSearchPath;
4149  }
4150  else
4151  {
4152  /*
4153  * In normal mode, arrange for a callback on any syscache invalidation
4154  * of pg_namespace rows.
4155  */
4158  (Datum) 0);
4159  /* Force search path to be recomputed on next use */
4160  baseSearchPathValid = false;
4161  }
4162 }
4163 
4164 /*
4165  * NamespaceCallback
4166  * Syscache inval callback function
4167  */
4168 static void
4169 NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue)
4170 {
4171  /* Force search path to be recomputed on next use */
4172  baseSearchPathValid = false;
4173 }
4174 
4175 /*
4176  * Fetch the active search path. The return value is a palloc'ed list
4177  * of OIDs; the caller is responsible for freeing this storage as
4178  * appropriate.
4179  *
4180  * The returned list includes the implicitly-prepended namespaces only if
4181  * includeImplicit is true.
4182  *
4183  * Note: calling this may result in a CommandCounterIncrement operation,
4184  * if we have to create or clean out the temp namespace.
4185  */
4186 List *
4187 fetch_search_path(bool includeImplicit)
4188 {
4189  List *result;
4190 
4192 
4193  /*
4194  * If the temp namespace should be first, force it to exist. This is so
4195  * that callers can trust the result to reflect the actual default
4196  * creation namespace. It's a bit bogus to do this here, since
4197  * current_schema() is supposedly a stable function without side-effects,
4198  * but the alternatives seem worse.
4199  */
4201  {
4204  }
4205 
4206  result = list_copy(activeSearchPath);
4207  if (!includeImplicit)
4208  {
4209  while (result && linitial_oid(result) != activeCreationNamespace)
4210  result = list_delete_first(result);
4211  }
4212 
4213  return result;
4214 }
4215 
4216 /*
4217  * Fetch the active search path into a caller-allocated array of OIDs.
4218  * Returns the number of path entries. (If this is more than sarray_len,
4219  * then the data didn't fit and is not all stored.)
4220  *
4221  * The returned list always includes the implicitly-prepended namespaces,
4222  * but never includes the temp namespace. (This is suitable for existing
4223  * users, which would want to ignore the temp namespace anyway.) This
4224  * definition allows us to not worry about initializing the temp namespace.
4225  */
4226 int
4227 fetch_search_path_array(Oid *sarray, int sarray_len)
4228 {
4229  int count = 0;
4230  ListCell *l;
4231 
4233 
4234  foreach(l, activeSearchPath)
4235  {
4236  Oid namespaceId = lfirst_oid(l);
4237 
4238  if (namespaceId == myTempNamespace)
4239  continue; /* do not include temp namespace */
4240 
4241  if (count < sarray_len)
4242  sarray[count] = namespaceId;
4243  count++;
4244  }
4245 
4246  return count;
4247 }
4248 
4249 
4250 /*
4251  * Export the FooIsVisible functions as SQL-callable functions.
4252  *
4253  * Note: as of Postgres 8.4, these will silently return NULL if called on
4254  * a nonexistent object OID, rather than failing. This is to avoid race
4255  * condition errors when a query that's scanning a catalog using an MVCC
4256  * snapshot uses one of these functions. The underlying IsVisible functions
4257  * always use an up-to-date snapshot and so might see the object as already
4258  * gone when it's still visible to the transaction snapshot. (There is no race
4259  * condition in the current coding because we don't accept sinval messages
4260  * between the SearchSysCacheExists test and the subsequent lookup.)
4261  */
4262 
4263 Datum
4265 {
4266  Oid oid = PG_GETARG_OID(0);
4267 
4269  PG_RETURN_NULL();
4270 
4272 }
4273 
4274 Datum
4276 {
4277  Oid oid = PG_GETARG_OID(0);
4278 
4280  PG_RETURN_NULL();
4281 
4283 }
4284 
4285 Datum
4287 {
4288  Oid oid = PG_GETARG_OID(0);
4289 
4291  PG_RETURN_NULL();
4292 
4294 }
4295 
4296 Datum
4298 {
4299  Oid oid = PG_GETARG_OID(0);
4300 
4302  PG_RETURN_NULL();
4303 
4305 }
4306 
4307 Datum
4309 {
4310  Oid oid = PG_GETARG_OID(0);
4311 
4313  PG_RETURN_NULL();
4314 
4316 }
4317 
4318 Datum
4320 {
4321  Oid oid = PG_GETARG_OID(0);
4322 
4324  PG_RETURN_NULL();
4325 
4327 }
4328 
4329 Datum
4331 {
4332  Oid oid = PG_GETARG_OID(0);
4333 
4335  PG_RETURN_NULL();
4336 
4338 }
4339 
4340 Datum
4342 {
4343  Oid oid = PG_GETARG_OID(0);
4344 
4346  PG_RETURN_NULL();
4347 
4349 }
4350 
4351 Datum
4353 {
4354  Oid oid = PG_GETARG_OID(0);
4355 
4357  PG_RETURN_NULL();
4358 
4360 }
4361 
4362 Datum
4364 {
4365  Oid oid = PG_GETARG_OID(0);
4366 
4368  PG_RETURN_NULL();
4369 
4371 }
4372 
4373 Datum
4375 {
4376  Oid oid = PG_GETARG_OID(0);
4377 
4379  PG_RETURN_NULL();
4380 
4382 }
4383 
4384 Datum
4386 {
4387  Oid oid = PG_GETARG_OID(0);
4388 
4390  PG_RETURN_NULL();
4391 
4393 }
4394 
4395 Datum
4397 {
4398  Oid oid = PG_GETARG_OID(0);
4399 
4401  PG_RETURN_NULL();
4402 
4404 }
4405 
4406 Datum
4408 {
4410 }
4411 
4412 Datum
4414 {
4415  Oid oid = PG_GETARG_OID(0);
4416 
4418 }
Value * makeString(char *str)
Definition: value.c:53
void ResetTempTableNamespace(void)
Definition: namespace.c:4066
#define NIL
Definition: pg_list.h:69
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:138
static bool baseSearchPathValid
Definition: namespace.c:152
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
int n_members
Definition: catcache.h:176
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3024
#define DEBUG1
Definition: elog.h:25
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2872
BackendId MyBackendId
Definition: globals.c:82
Oid relnamespace
Definition: pg_class.h:32
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define AssertState(condition)
Definition: c.h:702
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:62
void AcceptInvalidationMessages(void)
Definition: inval.c:679
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10488
FormData_pg_ts_config * Form_pg_ts_config
Definition: pg_ts_config.h:38
int LOCKMODE
Definition: lockdefs.h:26
Oid GetUserId(void)
Definition: miscinit.c:379
Oid TypenameGetTypid(const char *typname)
Definition: namespace.c:767
Datum pg_type_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4275
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
Oid oprid(Operator op)
Definition: parse_oper.c:245
#define GUC_check_errdetail
Definition: guc.h:410
Oid RelnameGetRelid(const char *relname)
Definition: namespace.c:673
Datum pg_my_temp_schema(PG_FUNCTION_ARGS)
Definition: namespace.c:4407
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2975
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3161
#define PointerGetDatum(X)
Definition: postgres.h:539
static Oid myTempToastNamespace
Definition: namespace.c:182
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2915
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:2744
Datum pg_opclass_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4308
void GetTempNamespaceState(Oid *tempNamespaceId, Oid *tempToastNamespaceId)
Definition: namespace.c:3253
void PushOverrideSearchPath(OverrideSearchPath *newpath)
Definition: namespace.c:3412
Datum pg_conversion_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4341
bool is_encoding_supported_by_icu(int encoding)
Definition: encnames.c:455
#define PERFORM_DELETION_SKIP_ORIGINAL
Definition: dependency.h:192
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:846
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:1160
Definition: nodes.h:517
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:2658
bool OperatorIsVisible(Oid oprid)
Definition: namespace.c:1726
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
int GetTempNamespaceBackendId(Oid namespaceId)
Definition: namespace.c:3214
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2788
bool FunctionIsVisible(Oid funcid)
Definition: namespace.c:1393
static Oid namespaceUser
Definition: namespace.c:149
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3042
Oid CollationGetCollid(const char *collname)
Definition: namespace.c:1993
uint32 SubTransactionId
Definition: c.h:478
List * lcons_oid(Oid datum, List *list)
Definition: list.c:295
int16 pronargs
Definition: pg_proc.h:80
unsigned int Oid
Definition: postgres_ext.h:31
bool RecoveryInProgress(void)
Definition: xlog.c:7939
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1779
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:605
int fetch_search_path_array(Oid *sarray, int sarray_len)
Definition: namespace.c:4227
void AbortOutOfAnyTransaction(void)
Definition: xact.c:4318
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4686
#define GetSysCacheOid3(cacheId, key1, key2, key3)
Definition: syscache.h:195
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:634
#define lsecond(l)
Definition: pg_list.h:116
signed int int32
Definition: c.h:313
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:193
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:3648
char * schemaname
Definition: primnodes.h:68
#define GetSysCacheOid1(cacheId, key1)
Definition: syscache.h:191
#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:139
#define NAMEDATALEN
Oid ConversionGetConid(const char *conname)
Definition: namespace.c:2078
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:55
char * relname
Definition: primnodes.h:69
Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
Definition: namespace.c:1464
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:3348
Oid OpfamilynameGetOpfid(Oid amid, const char *opfname)
Definition: namespace.c:1862
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:182
Oid args[FLEXIBLE_ARRAY_MEMBER]
Definition: namespace.h:37
void pfree(void *pointer)
Definition: mcxt.c:1031
#define linitial(l)
Definition: pg_list.h:111
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#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:922
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1134
void InitializeSearchPath(void)
Definition: namespace.c:4129
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:3336
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1687
OverrideSearchPath * GetOverrideSearchPath(MemoryContext context)
Definition: namespace.c:3300
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2056
Datum pg_opfamily_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4319
FormData_pg_ts_dict * Form_pg_ts_dict
Definition: pg_ts_dict.h:41
Oid GetTempToastNamespace(void)
Definition: namespace.c:3239
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
Oid get_ts_template_oid(List *names, bool missing_ok)
Definition: namespace.c:2532
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
void SetTempNamespaceState(Oid tempNamespaceId, Oid tempToastNamespaceId)
Definition: namespace.c:3269
#define NoLock
Definition: lockdefs.h:34
#define PG_GETARG_OID(n)
Definition: fmgr.h:245
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3290
Datum pg_function_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4286
#define CStringGetDatum(X)
Definition: postgres.h:561
char string[11]
Definition: preproc-type.c:46
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:856
void before_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:331
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:300
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:227
unsigned int uint32
Definition: c.h:325
static SubTransactionId myTempNamespaceSubID
Definition: namespace.c:184
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3137
#define ACL_USAGE
Definition: parsenodes.h:82
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:209
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:1145
struct _FuncCandidateList * next
Definition: namespace.h:30
static void NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue)
Definition: namespace.c:4169
Datum pg_ts_config_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4396
#define lnext(lc)
Definition: pg_list.h:105
static bool activeTempCreationPending
Definition: namespace.c:139
#define ereport(elevel, rest)
Definition: elog.h:122
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:4385
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2947
void UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:877
static Oid baseCreationNamespace
Definition: namespace.c:145
static void InitTempTableNamespace(void)
Definition: namespace.c:3798
bool isTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3149
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
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:1112
char * NameListToString(List *names)
Definition: namespace.c:3082
static int elevel
Definition: vacuumlazy.c:144
char * NameListToQuotedString(List *names)
Definition: namespace.c:3116
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:527
#define ReleaseSysCacheList(x)
Definition: syscache.h:216
void PopOverrideSearchPath(void)
Definition: namespace.c:3471
#define InvalidBackendId
Definition: backendid.h:23
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:49
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:1389
void * palloc0(Size size)
Definition: mcxt.c:955
AclResult
Definition: acl.h:178
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:324
uintptr_t Datum
Definition: postgres.h:365
void CommandCounterIncrement(void)
Definition: xact.c:914
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
FormData_pg_ts_parser * Form_pg_ts_parser
Definition: pg_ts_parser.h:53
FormData_pg_conversion * Form_pg_conversion
Definition: pg_conversion.h:56
int GetDatabaseEncoding(void)
Definition: mbutils.c:1004
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
#define list_make1_oid(x1)
Definition: pg_list.h:151
Datum pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4363
Oid MyDatabaseId
Definition: globals.c:86
bool OpclassIsVisible(Oid opcid)
Definition: namespace.c:1812
uint64 SharedInvalidMessageCounter
Definition: sinval.c:26
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:132
#define InvalidOid
Definition: postgres_ext.h:36
void assign_search_path(const char *newval, void *extra)
Definition: namespace.c:4113
Datum pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4374
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:753
List * lcons(void *datum, List *list)
Definition: list.c:259
bool ConversionIsVisible(Oid conid)
Definition: namespace.c:2110
bool OverrideSearchPathMatchesCurrent(OverrideSearchPath *path)
Definition: namespace.c:3352
#define Max(x, y)
Definition: c.h:851
Datum pg_is_other_temp_schema(PG_FUNCTION_ARGS)
Definition: namespace.c:4413
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4636
Oid get_ts_parser_oid(List *names, bool missing_ok)
Definition: namespace.c:2279
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1010
bool TypeIsVisible(Oid typid)
Definition: namespace.c:796
#define PERFORM_DELETION_QUIETLY
Definition: dependency.h:191
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:641
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:4748
void StartTransactionCommand(void)
Definition: xact.c:2673
Datum pg_operator_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4297
static void RemoveTempRelations(Oid tempNamespaceId)
Definition: namespace.c:4022
#define linitial_oid(l)
Definition: pg_list.h:113
bool check_search_path(char **newval, void **extra, GucSource source)
Definition: namespace.c:4079
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
static int list_length(const List *l)
Definition: pg_list.h:89
#define newval
Oid FindDefaultConversionProc(int32 for_encoding, int32 to_encoding)
Definition: namespace.c:3621
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:184
#define InvalidSubTransactionId
Definition: c.h:480
int32 encoding
Definition: pg_database.h:33
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:82
const char * name
Definition: encode.c:521
static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames, int **argnumbers)
Definition: namespace.c:1285
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:49
Datum pg_collation_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4330
#define nodeTag(nodeptr)
Definition: nodes.h:522
char relpersistence
Definition: primnodes.h:72
Oid get_conversion_oid(List *name, bool missing_ok)
Definition: namespace.c:3566
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:372
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
static List * activeSearchPath
Definition: namespace.c:133
#define Int32GetDatum(X)
Definition: postgres.h:462
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:797
#define SearchSysCacheList3(cacheId, key1, key2, key3)
Definition: syscache.h:213
bool RelationIsVisible(Oid relid)
Definition: namespace.c:701
bool isOtherTempNamespace(Oid namespaceId)
Definition: namespace.c:3198
void list_free(List *list)
Definition: list.c:1133
FormData_pg_ts_template * Form_pg_ts_template
int i
#define ACL_CREATE_TEMP
Definition: parsenodes.h:85
ObjectType get_relkind_objtype(char relkind)
#define NameStr(name)
Definition: c.h:576
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:121
bool isAnyTempNamespace(Oid namespaceId)
Definition: namespace.c:3175
#define PG_FUNCTION_ARGS
Definition: fmgr.h:163
HeapTupleData tuple
Definition: catcache.h:121
#define elog
Definition: elog.h:219
void AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: namespace.c:3962
Oid FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
Datum pg_statistics_obj_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4352
#define PERFORM_DELETION_SKIP_EXTENSIONS
Definition: dependency.h:193
Datum pg_table_is_visible(PG_FUNCTION_ARGS)
Definition: namespace.c:4264
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:81
void AtEOXact_Namespace(bool isCommit, bool parallel)
Definition: namespace.c:3907
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3512
Definition: pg_list.h:45
#define PG_RETURN_OID(x)
Definition: fmgr.h:325
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4187
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:421
#define PG_RETURN_NULL()
Definition: fmgr.h:310
char * catalogname
Definition: primnodes.h:67
static void RemoveTempRelationsCallback(int code, Datum arg)
Definition: namespace.c:4048
#define offsetof(type, field)
Definition: c.h:622
Oid RangeVarGetCreationNamespace(const RangeVar *newRelation)
Definition: namespace.c:440
FormData_pg_statistic_ext * Form_pg_statistic_ext
#define lfirst_oid(lc)
Definition: pg_list.h:108
Oid NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
Definition: pg_namespace.c:42
List * list_delete_first(List *list)
Definition: list.c:666
Oid LookupNamespaceNoError(const char *nspname)
Definition: namespace.c:2842
#define PERFORM_DELETION_INTERNAL
Definition: dependency.h:189