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