]> granicus.if.org Git - postgresql/blobdiff - src/backend/catalog/namespace.c
Update copyright for 2016
[postgresql] / src / backend / catalog / namespace.c
index 10ad82b79e93c423f9dd73a39e433602f6fc5d83..8b105fe62f6ac89800ab8f541daba1bd3097d477 100644 (file)
@@ -9,7 +9,7 @@
  * and implementing search-path-controlled searches.
  *
  *
- * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
  */
 #include "postgres.h"
 
+#include "access/htup_details.h"
+#include "access/parallel.h"
 #include "access/xact.h"
+#include "access/xlog.h"
 #include "catalog/dependency.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_conversion.h"
  * when we are obeying an override search path spec that says not to use the
  * temp namespace, or the temp namespace is included in the explicit list.)
  *
- * 2. The system catalog namespace is always searched. If the system
+ * 2. The system catalog namespace is always searched.  If the system
  * namespace is present in the explicit path then it will be searched in
  * the specified order; otherwise it will be searched after TEMP tables and
- * *before* the explicit list. (It might seem that the system namespace
+ * *before* the explicit list.  (It might seem that the system namespace
  * should be implicitly last, but this behavior appears to be required by
  * SQL99.  Also, this provides a way to search the system namespace first
  * without thereby making it the default creation target namespace.)
@@ -85,7 +89,7 @@
  * to refer to the current backend's temp namespace.  This is usually also
  * ignorable if the temp namespace hasn't been set up, but there's a special
  * case: if "pg_temp" appears first then it should be the default creation
- * target.     We kluge this case a little bit so that the temp namespace isn't
+ * target.  We kluge this case a little bit so that the temp namespace isn't
  * set up until the first attempt to create something in it.  (The reason for
  * klugery is that we can't create the temp namespace outside a transaction,
  * but initial GUC processing of search_path happens outside a transaction.)
  * In bootstrap mode, the search path is set equal to "pg_catalog", so that
  * the system namespace is the only one searched or inserted into.
  * initdb is also careful to set search_path to "pg_catalog" for its
- * post-bootstrap standalone backend runs.     Otherwise the default search
+ * post-bootstrap standalone backend runs.  Otherwise the default search
  * path is determined by GUC.  The factory default path contains the PUBLIC
  * namespace (if it exists), preceded by the user's personal namespace
  * (if one exists).
@@ -160,13 +164,13 @@ static List *overrideStack = NIL;
 /*
  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
  * in a particular backend session (this happens when a CREATE TEMP TABLE
- * command is first executed). Thereafter it's the OID of the temp namespace.
+ * command is first executed).  Thereafter it's the OID of the temp namespace.
  *
  * myTempToastNamespace is the OID of the namespace for my temp tables' toast
- * tables.     It is set when myTempNamespace is, and is InvalidOid before that.
+ * tables.  It is set when myTempNamespace is, and is InvalidOid before that.
  *
  * myTempNamespaceSubID shows whether we've created the TEMP namespace in the
- * current subtransaction.     The flag propagates up the subtransaction tree,
+ * current subtransaction.  The flag propagates up the subtransaction tree,
  * so the main transaction will correctly recognize the flag if all
  * intermediate subtransactions commit.  When it is InvalidSubTransactionId,
  * we either haven't made the TEMP namespace yet, or have successfully
@@ -216,8 +220,8 @@ Datum               pg_is_other_temp_schema(PG_FUNCTION_ARGS);
  *             Given a RangeVar describing an existing relation,
  *             select the proper namespace and look up the relation OID.
  *
- * If the relation is not found, return InvalidOid if missing_ok = true,
- * otherwise raise an error.
+ * If the schema or relation is not found, return InvalidOid if missing_ok
+ * = true, otherwise raise an error.
  *
  * If nowait = true, throw an error if we'd have to wait for a lock.
  *
@@ -248,7 +252,7 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
        }
 
        /*
-        * DDL operations can change the results of a name lookup.      Since all such
+        * DDL operations can change the results of a name lookup.  Since all such
         * operations will generate invalidation messages, we keep track of
         * whether any such messages show up while we're performing the operation,
         * and retry until either (1) no more invalidation messages show up or (2)
@@ -257,10 +261,10 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
         * But if lockmode = NoLock, then we assume that either the caller is OK
         * with the answer changing under them, or that they already hold some
         * appropriate lock, and therefore return the first answer we get without
-        * checking for invalidation messages.  Also, if the requested lock is
-        * already held, no LockRelationOid will not AcceptInvalidationMessages,
-        * so we may fail to notice a change.  We could protect against that case
-        * by calling AcceptInvalidationMessages() before beginning this loop, but
+        * checking for invalidation messages.  Also, if the requested lock is
+        * already held, LockRelationOid will not AcceptInvalidationMessages, so
+        * we may fail to notice a change.  We could protect against that case by
+        * calling AcceptInvalidationMessages() before beginning this loop, but
         * that would add a significant amount overhead, so for now we don't.
         */
        for (;;)
@@ -290,7 +294,12 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
                                {
                                        Oid                     namespaceId;
 
-                                       namespaceId = LookupExplicitNamespace(relation->schemaname);
+                                       namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
+
+                                       /*
+                                        * For missing_ok, allow a non-existant schema name to
+                                        * return InvalidOid.
+                                        */
                                        if (namespaceId != myTempNamespace)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
@@ -305,8 +314,11 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
                        Oid                     namespaceId;
 
                        /* use exact schema given */
-                       namespaceId = LookupExplicitNamespace(relation->schemaname);
-                       relId = get_relname_relid(relation->relname, namespaceId);
+                       namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
+                       if (missing_ok && !OidIsValid(namespaceId))
+                               relId = InvalidOid;
+                       else
+                               relId = get_relname_relid(relation->relname, namespaceId);
                }
                else
                {
@@ -386,7 +398,7 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
                        break;
 
                /*
-                * Something may have changed.  Let's repeat the name lookup, to make
+                * Something may have changed.  Let's repeat the name lookup, to make
                 * sure this name still references the same relation it did
                 * previously.
                 */
@@ -492,7 +504,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
  * the same name which already exists in that namespace, or to InvalidOid if
  * no such relation exists.
  *
- * If lockmode != NoLock, the specified lock mode is acquire on the existing
+ * If lockmode != NoLock, the specified lock mode is acquired on the existing
  * relation, if any, provided that the current user owns the target relation.
  * However, if lockmode != NoLock and the user does not own the target
  * relation, we throw an ERROR, as we must not try to lock relations the
@@ -619,7 +631,7 @@ RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
        switch (newRelation->relpersistence)
        {
                case RELPERSISTENCE_TEMP:
-                       if (!isTempOrToastNamespace(nspid))
+                       if (!isTempOrTempToastNamespace(nspid))
                        {
                                if (isAnyTempNamespace(nspid))
                                        ereport(ERROR,
@@ -632,7 +644,7 @@ RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
                        }
                        break;
                case RELPERSISTENCE_PERMANENT:
-                       if (isTempOrToastNamespace(nspid))
+                       if (isTempOrTempToastNamespace(nspid))
                                newRelation->relpersistence = RELPERSISTENCE_TEMP;
                        else if (isAnyTempNamespace(nspid))
                                ereport(ERROR,
@@ -859,7 +871,7 @@ TypeIsVisible(Oid typid)
  * and the returned nvargs will always be zero.
  *
  * If expand_defaults is true, functions that could match after insertion of
- * default argument values will also be retrieved.     In this case the returned
+ * default argument values will also be retrieved.  In this case the returned
  * structs could have nargs > passed-in nargs, and ndargs is set to the number
  * of additional args (which can be retrieved from the function's
  * proargdefaults entry).
@@ -896,10 +908,15 @@ TypeIsVisible(Oid typid)
  * with oid = 0 that represents a set of such conflicting candidates.
  * The caller might end up discarding such an entry anyway, but if it selects
  * such an entry it should react as though the call were ambiguous.
+ *
+ * If missing_ok is true, an empty list (NULL) is returned if the name was
+ * schema- qualified with a schema that does not exist.  Likewise if no
+ * candidate is found for other reasons.
  */
 FuncCandidateList
 FuncnameGetCandidates(List *names, int nargs, List *argnames,
-                                         bool expand_variadic, bool expand_defaults)
+                                         bool expand_variadic, bool expand_defaults,
+                                         bool missing_ok)
 {
        FuncCandidateList resultList = NULL;
        bool            any_special = false;
@@ -918,7 +935,9 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
        if (schemaname)
        {
                /* use exact schema given */
-               namespaceId = LookupExplicitNamespace(schemaname);
+               namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+               if (!OidIsValid(namespaceId))
+                       return NULL;
        }
        else
        {
@@ -1015,7 +1034,7 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
                         * Call uses positional notation
                         *
                         * Check if function is variadic, and get variadic element type if
-                        * so.  If expand_variadic is false, we should just ignore
+                        * so.  If expand_variadic is false, we should just ignore
                         * variadic-ness.
                         */
                        if (pronargs <= nargs && expand_variadic)
@@ -1057,8 +1076,8 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
                 */
                effective_nargs = Max(pronargs, nargs);
                newResult = (FuncCandidateList)
-                       palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
-                                  effective_nargs * sizeof(Oid));
+                       palloc(offsetof(struct _FuncCandidateList, args) +
+                                  effective_nargs * sizeof(Oid));
                newResult->pathpos = pathpos;
                newResult->oid = HeapTupleGetOid(proctup);
                newResult->nargs = effective_nargs;
@@ -1145,7 +1164,7 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
                        if (prevResult)
                        {
                                /*
-                                * We have a match with a previous result.      Decide which one
+                                * We have a match with a previous result.  Decide which one
                                 * to keep, or mark it ambiguous if we can't decide.  The
                                 * logic here is preference > 0 means prefer the old result,
                                 * preference < 0 means prefer the new, preference = 0 means
@@ -1404,7 +1423,7 @@ FunctionIsVisible(Oid funcid)
                visible = false;
 
                clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-                                                                         nargs, NIL, false, false);
+                                                                         nargs, NIL, false, false, false);
 
                for (; clist; clist = clist->next)
                {
@@ -1433,7 +1452,8 @@ FunctionIsVisible(Oid funcid)
  * a postfix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
- * namespace search path.
+ * namespace search path.  If the name is schema-qualified and the given
+ * schema does not exist, InvalidOid is returned.
  */
 Oid
 OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
@@ -1450,21 +1470,26 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
        {
                /* search only in exact schema given */
                Oid                     namespaceId;
-               HeapTuple       opertup;
 
-               namespaceId = LookupExplicitNamespace(schemaname);
-               opertup = SearchSysCache4(OPERNAMENSP,
-                                                                 CStringGetDatum(opername),
-                                                                 ObjectIdGetDatum(oprleft),
-                                                                 ObjectIdGetDatum(oprright),
-                                                                 ObjectIdGetDatum(namespaceId));
-               if (HeapTupleIsValid(opertup))
+               namespaceId = LookupExplicitNamespace(schemaname, true);
+               if (OidIsValid(namespaceId))
                {
-                       Oid                     result = HeapTupleGetOid(opertup);
+                       HeapTuple       opertup;
 
-                       ReleaseSysCache(opertup);
-                       return result;
+                       opertup = SearchSysCache4(OPERNAMENSP,
+                                                                         CStringGetDatum(opername),
+                                                                         ObjectIdGetDatum(oprleft),
+                                                                         ObjectIdGetDatum(oprright),
+                                                                         ObjectIdGetDatum(namespaceId));
+                       if (HeapTupleIsValid(opertup))
+                       {
+                               Oid                     result = HeapTupleGetOid(opertup);
+
+                               ReleaseSysCache(opertup);
+                               return result;
+                       }
                }
+
                return InvalidOid;
        }
 
@@ -1530,10 +1555,10 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
  * identical entries in later namespaces.
  *
  * The returned items always have two args[] entries --- one or the other
- * will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too.
+ * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
  */
 FuncCandidateList
-OpernameGetCandidates(List *names, char oprkind)
+OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
 {
        FuncCandidateList resultList = NULL;
        char       *resultSpace = NULL;
@@ -1550,7 +1575,9 @@ OpernameGetCandidates(List *names, char oprkind)
        if (schemaname)
        {
                /* use exact schema given */
-               namespaceId = LookupExplicitNamespace(schemaname);
+               namespaceId = LookupExplicitNamespace(schemaname, missing_schema_ok);
+               if (missing_schema_ok && !OidIsValid(namespaceId))
+                       return NULL;
        }
        else
        {
@@ -1571,7 +1598,8 @@ OpernameGetCandidates(List *names, char oprkind)
         * separate palloc for each operator, but profiling revealed that the
         * pallocs used an unreasonably large fraction of parsing time.
         */
-#define SPACE_PER_OP MAXALIGN(sizeof(struct _FuncCandidateList) + sizeof(Oid))
+#define SPACE_PER_OP MAXALIGN(offsetof(struct _FuncCandidateList, args) + \
+                                                         2 * sizeof(Oid))
 
        if (catlist->n_members > 0)
                resultSpace = palloc(catlist->n_members * SPACE_PER_OP);
@@ -1719,7 +1747,7 @@ OperatorIsVisible(Oid oprid)
                 * If it is in the path, it might still not be visible; it could be
                 * hidden by another operator of the same name and arguments earlier
                 * in the path.  So we must do a slow check to see if this is the same
-                * operator that would be found by OpernameGetOprId.
+                * operator that would be found by OpernameGetOprid.
                 */
                char       *oprname = NameStr(oprform->oprname);
 
@@ -2092,10 +2120,13 @@ get_ts_parser_oid(List *names, bool missing_ok)
        if (schemaname)
        {
                /* use exact schema given */
-               namespaceId = LookupExplicitNamespace(schemaname);
-               prsoid = GetSysCacheOid2(TSPARSERNAMENSP,
-                                                                PointerGetDatum(parser_name),
-                                                                ObjectIdGetDatum(namespaceId));
+               namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+               if (missing_ok && !OidIsValid(namespaceId))
+                       prsoid = InvalidOid;
+               else
+                       prsoid = GetSysCacheOid2(TSPARSERNAMENSP,
+                                                                        PointerGetDatum(parser_name),
+                                                                        ObjectIdGetDatum(namespaceId));
        }
        else
        {
@@ -2215,10 +2246,13 @@ get_ts_dict_oid(List *names, bool missing_ok)
        if (schemaname)
        {
                /* use exact schema given */
-               namespaceId = LookupExplicitNamespace(schemaname);
-               dictoid = GetSysCacheOid2(TSDICTNAMENSP,
-                                                                 PointerGetDatum(dict_name),
-                                                                 ObjectIdGetDatum(namespaceId));
+               namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+               if (missing_ok && !OidIsValid(namespaceId))
+                       dictoid = InvalidOid;
+               else
+                       dictoid = GetSysCacheOid2(TSDICTNAMENSP,
+                                                                         PointerGetDatum(dict_name),
+                                                                         ObjectIdGetDatum(namespaceId));
        }
        else
        {
@@ -2339,10 +2373,13 @@ get_ts_template_oid(List *names, bool missing_ok)
        if (schemaname)
        {
                /* use exact schema given */
-               namespaceId = LookupExplicitNamespace(schemaname);
-               tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP,
-                                                                 PointerGetDatum(template_name),
-                                                                 ObjectIdGetDatum(namespaceId));
+               namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+               if (missing_ok && !OidIsValid(namespaceId))
+                       tmploid = InvalidOid;
+               else
+                       tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP,
+                                                                         PointerGetDatum(template_name),
+                                                                         ObjectIdGetDatum(namespaceId));
        }
        else
        {
@@ -2462,10 +2499,13 @@ get_ts_config_oid(List *names, bool missing_ok)
        if (schemaname)
        {
                /* use exact schema given */
-               namespaceId = LookupExplicitNamespace(schemaname);
-               cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP,
-                                                                PointerGetDatum(config_name),
-                                                                ObjectIdGetDatum(namespaceId));
+               namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+               if (missing_ok && !OidIsValid(namespaceId))
+                       cfgoid = InvalidOid;
+               else
+                       cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP,
+                                                                        PointerGetDatum(config_name),
+                                                                        ObjectIdGetDatum(namespaceId));
        }
        else
        {
@@ -2499,7 +2539,7 @@ get_ts_config_oid(List *names, bool missing_ok)
 /*
  * TSConfigIsVisible
  *             Determine whether a text search configuration (identified by OID)
- *             is visible in the current search path.  Visible means "would be found
+ *             is visible in the current search path.  Visible means "would be found
  *             by searching for the unqualified text search configuration name".
  */
 bool
@@ -2635,7 +2675,10 @@ LookupNamespaceNoError(const char *nspname)
        if (strcmp(nspname, "pg_temp") == 0)
        {
                if (OidIsValid(myTempNamespace))
+               {
+                       InvokeNamespaceSearchHook(myTempNamespace, true);
                        return myTempNamespace;
+               }
 
                /*
                 * Since this is used only for looking up existing objects, there is
@@ -2653,10 +2696,10 @@ LookupNamespaceNoError(const char *nspname)
  *             Process an explicitly-specified schema name: look up the schema
  *             and verify we have USAGE (lookup) rights in it.
  *
- * Returns the namespace OID.  Raises ereport if any problem.
+ * Returns the namespace OID
  */
 Oid
-LookupExplicitNamespace(const char *nspname)
+LookupExplicitNamespace(const char *nspname, bool missing_ok)
 {
        Oid                     namespaceId;
        AclResult       aclresult;
@@ -2670,17 +2713,20 @@ LookupExplicitNamespace(const char *nspname)
                /*
                 * Since this is used only for looking up existing objects, there is
                 * no point in trying to initialize the temp namespace here; and doing
-                * so might create problems for some callers. Just fall through and
-                * give the "does not exist" error.
+                * so might create problems for some callers --- just fall through.
                 */
        }
 
-       namespaceId = get_namespace_oid(nspname, false);
+       namespaceId = get_namespace_oid(nspname, missing_ok);
+       if (missing_ok && !OidIsValid(namespaceId))
+               return InvalidOid;
 
        aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
        if (aclresult != ACLCHECK_OK)
                aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                                           nspname);
+       /* Schema search hook for this lookup */
+       InvokeNamespaceSearchHook(namespaceId, true);
 
        return namespaceId;
 }
@@ -2723,24 +2769,13 @@ LookupCreationNamespace(const char *nspname)
 /*
  * Common checks on switching namespaces.
  *
- * We complain if (1) the old and new namespaces are the same, (2) either the
- * old or new namespaces is a temporary schema (or temporary toast schema), or
- * (3) either the old or new namespaces is the TOAST schema.
+ * We complain if either the old or new namespaces is a temporary schema
+ * (or temporary toast schema), or if either the old or new namespaces is the
+ * TOAST schema.
  */
 void
-CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
+CheckSetNamespace(Oid oldNspOid, Oid nspOid)
 {
-       if (oldNspOid == nspOid)
-               ereport(ERROR,
-                               (classid == RelationRelationId ?
-                                errcode(ERRCODE_DUPLICATE_TABLE) :
-                                classid == ProcedureRelationId ?
-                                errcode(ERRCODE_DUPLICATE_FUNCTION) :
-                                errcode(ERRCODE_DUPLICATE_OBJECT),
-                                errmsg("%s is already in schema \"%s\"",
-                                               getObjectDescriptionOids(classid, objid),
-                                               get_namespace_name(nspOid))));
-
        /* disallow renaming into or out of temp schemas */
        if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
                ereport(ERROR,
@@ -2812,7 +2847,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
 /*
  * get_namespace_oid - given a namespace name, look up the OID
  *
- * If missing_ok is false, throw an error if namespace name not found. If
+ * If missing_ok is false, throw an error if namespace name not found.  If
  * true, just return InvalidOid.
  */
 Oid
@@ -2891,7 +2926,7 @@ NameListToString(List *names)
                if (IsA(name, String))
                        appendStringInfoString(&string, strVal(name));
                else if (IsA(name, A_Star))
-                       appendStringInfoString(&string, "*");
+                       appendStringInfoChar(&string, '*');
                else
                        elog(ERROR, "unexpected node type in name list: %d",
                                 (int) nodeTag(name));
@@ -2949,11 +2984,11 @@ isTempToastNamespace(Oid namespaceId)
 }
 
 /*
- * isTempOrToastNamespace - is the given namespace my temporary-table
+ * isTempOrTempToastNamespace - is the given namespace my temporary-table
  *             namespace or my temporary-toast-table namespace?
  */
 bool
-isTempOrToastNamespace(Oid namespaceId)
+isTempOrTempToastNamespace(Oid namespaceId)
 {
        if (OidIsValid(myTempNamespace) &&
         (myTempNamespace == namespaceId || myTempToastNamespace == namespaceId))
@@ -2993,7 +3028,7 @@ bool
 isOtherTempNamespace(Oid namespaceId)
 {
        /* If it's my own temp namespace, say "false" */
-       if (isTempOrToastNamespace(namespaceId))
+       if (isTempOrTempToastNamespace(namespaceId))
                return false;
        /* Else, if it's any temp namespace, say "true" */
        return isAnyTempNamespace(namespaceId);
@@ -3027,7 +3062,7 @@ GetTempNamespaceBackendId(Oid namespaceId)
 
 /*
  * GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
- * which must already be assigned.     (This is only used when creating a toast
+ * which must already be assigned.  (This is only used when creating a toast
  * table for a temp table, so we must have already done InitTempTableNamespace)
  */
 Oid
@@ -3095,6 +3130,52 @@ CopyOverrideSearchPath(OverrideSearchPath *path)
        return result;
 }
 
+/*
+ * OverrideSearchPathMatchesCurrent - does path match current setting?
+ */
+bool
+OverrideSearchPathMatchesCurrent(OverrideSearchPath *path)
+{
+       ListCell   *lc,
+                          *lcp;
+
+       recomputeNamespacePath();
+
+       /* We scan down the activeSearchPath to see if it matches the input. */
+       lc = list_head(activeSearchPath);
+
+       /* If path->addTemp, first item should be my temp namespace. */
+       if (path->addTemp)
+       {
+               if (lc && lfirst_oid(lc) == myTempNamespace)
+                       lc = lnext(lc);
+               else
+                       return false;
+       }
+       /* If path->addCatalog, next item should be pg_catalog. */
+       if (path->addCatalog)
+       {
+               if (lc && lfirst_oid(lc) == PG_CATALOG_NAMESPACE)
+                       lc = lnext(lc);
+               else
+                       return false;
+       }
+       /* We should now be looking at the activeCreationNamespace. */
+       if (activeCreationNamespace != (lc ? lfirst_oid(lc) : InvalidOid))
+               return false;
+       /* The remainder of activeSearchPath should match path->schemas. */
+       foreach(lcp, path->schemas)
+       {
+               if (lc && lfirst_oid(lc) == lfirst_oid(lcp))
+                       lc = lnext(lc);
+               else
+                       return false;
+       }
+       if (lc)
+               return false;
+       return true;
+}
+
 /*
  * PushOverrideSearchPath - temporarily override the search path
  *
@@ -3103,8 +3184,8 @@ CopyOverrideSearchPath(OverrideSearchPath *path)
  *
  * It's possible that newpath->useTemp is set but there is no longer any
  * active temp namespace, if the path was saved during a transaction that
- * created a temp namespace and was later rolled back. In that case we just
- * ignore useTemp.     A plausible alternative would be to create a new temp
+ * created a temp namespace and was later rolled back.  In that case we just
+ * ignore useTemp.  A plausible alternative would be to create a new temp
  * namespace, but for existing callers that's not necessary because an empty
  * temp namespace wouldn't affect their results anyway.
  *
@@ -3137,7 +3218,7 @@ PushOverrideSearchPath(OverrideSearchPath *newpath)
                firstNS = linitial_oid(oidlist);
 
        /*
-        * Add any implicitly-searched namespaces to the list.  Note these go on
+        * Add any implicitly-searched namespaces to the list.  Note these go on
         * the front, not the back; also notice that we do not check USAGE
         * permissions for these.
         */
@@ -3225,7 +3306,9 @@ get_collation_oid(List *name, bool missing_ok)
        if (schemaname)
        {
                /* use exact schema given */
-               namespaceId = LookupExplicitNamespace(schemaname);
+               namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+               if (missing_ok && !OidIsValid(namespaceId))
+                       return InvalidOid;
 
                /* first try for encoding-specific entry, then any-encoding */
                colloid = GetSysCacheOid3(COLLNAMEENCNSP,
@@ -3295,10 +3378,13 @@ get_conversion_oid(List *name, bool missing_ok)
        if (schemaname)
        {
                /* use exact schema given */
-               namespaceId = LookupExplicitNamespace(schemaname);
-               conoid = GetSysCacheOid2(CONNAMENSP,
-                                                                PointerGetDatum(conversion_name),
-                                                                ObjectIdGetDatum(namespaceId));
+               namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+               if (missing_ok && !OidIsValid(namespaceId))
+                       conoid = InvalidOid;
+               else
+                       conoid = GetSysCacheOid2(CONNAMENSP,
+                                                                        PointerGetDatum(conversion_name),
+                                                                        ObjectIdGetDatum(namespaceId));
        }
        else
        {
@@ -3420,7 +3506,8 @@ recomputeNamespacePath(void)
                                if (OidIsValid(namespaceId) &&
                                        !list_member_oid(oidlist, namespaceId) &&
                                        pg_namespace_aclcheck(namespaceId, roleid,
-                                                                                 ACL_USAGE) == ACLCHECK_OK)
+                                                                                 ACL_USAGE) == ACLCHECK_OK &&
+                                       InvokeNamespaceSearchHook(namespaceId, false))
                                        oidlist = lappend_oid(oidlist, namespaceId);
                        }
                }
@@ -3429,7 +3516,8 @@ recomputeNamespacePath(void)
                        /* pg_temp --- substitute temp namespace, if any */
                        if (OidIsValid(myTempNamespace))
                        {
-                               if (!list_member_oid(oidlist, myTempNamespace))
+                               if (!list_member_oid(oidlist, myTempNamespace) &&
+                                       InvokeNamespaceSearchHook(myTempNamespace, false))
                                        oidlist = lappend_oid(oidlist, myTempNamespace);
                        }
                        else
@@ -3446,13 +3534,14 @@ recomputeNamespacePath(void)
                        if (OidIsValid(namespaceId) &&
                                !list_member_oid(oidlist, namespaceId) &&
                                pg_namespace_aclcheck(namespaceId, roleid,
-                                                                         ACL_USAGE) == ACLCHECK_OK)
+                                                                         ACL_USAGE) == ACLCHECK_OK &&
+                               InvokeNamespaceSearchHook(namespaceId, false))
                                oidlist = lappend_oid(oidlist, namespaceId);
                }
        }
 
        /*
-        * Remember the first member of the explicit list.      (Note: this is
+        * Remember the first member of the explicit list.  (Note: this is
         * nominally wrong if temp_missing, but we need it anyway to distinguish
         * explicit from implicit mention of pg_catalog.)
         */
@@ -3462,7 +3551,7 @@ recomputeNamespacePath(void)
                firstNS = linitial_oid(oidlist);
 
        /*
-        * Add any implicitly-searched namespaces to the list.  Note these go on
+        * Add any implicitly-searched namespaces to the list.  Note these go on
         * the front, not the back; also notice that we do not check USAGE
         * permissions for these.
         */
@@ -3517,7 +3606,7 @@ InitTempTableNamespace(void)
 
        /*
         * First, do permission check to see if we are authorized to make temp
-        * tables.      We use a nonstandard error message here since "databasename:
+        * tables.  We use a nonstandard error message here since "databasename:
         * permission denied" might be a tad cryptic.
         *
         * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
@@ -3536,9 +3625,9 @@ InitTempTableNamespace(void)
         * Do not allow a Hot Standby slave session to make temp tables.  Aside
         * from problems with modifying the system catalogs, there is a naming
         * conflict: pg_temp_N belongs to the session with BackendId N on the
-        * master, not to a slave session with the same BackendId.      We should not
+        * master, not to a slave session with the same BackendId.  We should not
         * be able to get here anyway due to XactReadOnly checks, but let's just
-        * make real sure.      Note that this also backstops various operations that
+        * make real sure.  Note that this also backstops various operations that
         * allow XactReadOnly transactions to modify temp tables; they'd need
         * RecoveryInProgress checks if not for this.
         */
@@ -3547,6 +3636,12 @@ InitTempTableNamespace(void)
                                (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
                                 errmsg("cannot create temporary tables during recovery")));
 
+       /* Parallel workers can't create temporary tables, either. */
+       if (IsParallelWorker())
+               ereport(ERROR,
+                               (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
+                                errmsg("cannot create temporary tables in parallel mode")));
+
        snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
 
        namespaceId = get_namespace_oid(namespaceName, true);
@@ -3610,7 +3705,7 @@ InitTempTableNamespace(void)
  * End-of-transaction cleanup for namespaces.
  */
 void
-AtEOXact_Namespace(bool isCommit)
+AtEOXact_Namespace(bool isCommit, bool parallel)
 {
        /*
         * If we abort the transaction in which a temp namespace was selected,
@@ -3620,10 +3715,10 @@ AtEOXact_Namespace(bool isCommit)
         * at backend shutdown.  (We only want to register the callback once per
         * session, so this is a good place to do it.)
         */
-       if (myTempNamespaceSubID != InvalidSubTransactionId)
+       if (myTempNamespaceSubID != InvalidSubTransactionId && !parallel)
        {
                if (isCommit)
-                       on_shmem_exit(RemoveTempRelationsCallback, 0);
+                       before_shmem_exit(RemoveTempRelationsCallback, 0);
                else
                {
                        myTempNamespace = InvalidOid;
@@ -3894,7 +3989,7 @@ fetch_search_path(bool includeImplicit)
        /*
         * If the temp namespace should be first, force it to exist.  This is so
         * that callers can trust the result to reflect the actual default
-        * creation namespace.  It's a bit bogus to do this here, since
+        * creation namespace.  It's a bit bogus to do this here, since
         * current_schema() is supposedly a stable function without side-effects,
         * but the alternatives seem worse.
         */
@@ -3916,7 +4011,7 @@ fetch_search_path(bool includeImplicit)
 
 /*
  * Fetch the active search path into a caller-allocated array of OIDs.
- * Returns the number of path entries. (If this is more than sarray_len,
+ * Returns the number of path entries.  (If this is more than sarray_len,
  * then the data didn't fit and is not all stored.)
  *
  * The returned list always includes the implicitly-prepended namespaces,
@@ -3955,8 +4050,8 @@ fetch_search_path_array(Oid *sarray, int sarray_len)
  * a nonexistent object OID, rather than failing.  This is to avoid race
  * condition errors when a query that's scanning a catalog using an MVCC
  * snapshot uses one of these functions.  The underlying IsVisible functions
- * operate on SnapshotNow semantics and so might see the object as already
- * gone when it's still visible to the MVCC snapshot.  (There is no race
+ * always use an up-to-date snapshot and so might see the object as already
+ * gone when it's still visible to the transaction snapshot.  (There is no race
  * condition in the current coding because we don't accept sinval messages
  * between the SearchSysCacheExists test and the subsequent lookup.)
  */