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