unchanged:
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -706,7 +706,7 @@ objectNamesToOids(ObjectType objtype, List *objnames)
 				char	   *nspname = strVal(lfirst(cell));
 				Oid			oid;
 
-				oid = get_namespace_oid(nspname, false);
+				oid = get_namespace_oid(nspname, InvalidOid, false);
 				objects = lappend_oid(objects, oid);
 			}
 			break;
@@ -1113,7 +1113,7 @@ SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
 		{
 			char	   *nspname = strVal(lfirst(nspcell));
 
-			iacls->nspid = get_namespace_oid(nspname, false);
+			iacls->nspid = get_namespace_oid(nspname, InvalidOid, false);
 
 			/*
 			 * We used to insist that the target role have CREATE privileges
@@ -3372,6 +3372,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
 					case OBJECT_MATVIEW:
 						msg = gettext_noop("permission denied for materialized view %s");
 						break;
+					case OBJECT_MODULE:
+						msg = gettext_noop("permission denied for module %s");
+						break;
 					case OBJECT_OPCLASS:
 						msg = gettext_noop("permission denied for operator class %s");
 						break;
@@ -3500,6 +3503,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
 					case OBJECT_MATVIEW:
 						msg = gettext_noop("must be owner of materialized view %s");
 						break;
+					case OBJECT_MODULE:
+						msg = gettext_noop("must be owner of module %s");
+						break;
 					case OBJECT_OPCLASS:
 						msg = gettext_noop("must be owner of operator class %s");
 						break;
unchanged:
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -473,7 +473,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
 			return myTempNamespace;
 		}
 		/* use exact schema given */
-		namespaceId = get_namespace_oid(newRelation->schemaname, false);
+		namespaceId = get_namespace_oid(newRelation->schemaname, InvalidOid, false);
 		/* we do not check for USAGE rights here! */
 	}
 	else if (newRelation->relpersistence == RELPERSISTENCE_TEMP)
@@ -945,9 +945,11 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 {
 	FuncCandidateList resultList = NULL;
 	bool		any_special = false;
-	char	   *schemaname;
+	char	   *nspname;
+	char	   *modulename;
 	char	   *funcname;
 	Oid			namespaceId;
+	Oid			moduleId;
 	CatCList   *catlist;
 	int			i;
 
@@ -955,19 +957,31 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 	Assert(nargs >= 0 || !(expand_variadic | expand_defaults));
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, &funcname);
+	DeconstructQualifiedName(names, &nspname, &modulename, &funcname, true);
 
-	if (schemaname)
+	if (nspname && modulename)
 	{
 		/* use exact schema given */
-		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		namespaceId = LookupExplicitNamespace(nspname, missing_ok);
 		if (!OidIsValid(namespaceId))
 			return NULL;
+
+		moduleId = get_namespace_oid(modulename, namespaceId, true);
+		if (!OidIsValid(moduleId))
+			return NULL;
+	}
+	else if (nspname)
+	{
+		moduleId = InvalidOid;
+		namespaceId = LookupExplicitNamespace(nspname, true);
+		if (!OidIsValid(namespaceId))
+			recomputeNamespacePath();
 	}
 	else
 	{
 		/* flag to indicate we need namespace search */
 		namespaceId = InvalidOid;
+		moduleId = InvalidOid;
 		recomputeNamespacePath();
 	}
 
@@ -987,9 +1001,15 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 		int		   *argnumbers = NULL;
 		FuncCandidateList newResult;
 
-		if (OidIsValid(namespaceId))
+		if (OidIsValid(moduleId))
 		{
-			/* Consider only procs in specified namespace */
+			/* Consider only procs in specified module */
+			if (procform->pronamespace != moduleId)
+				continue;
+		}
+		else if (OidIsValid(namespaceId))
+		{
+			/* Consider only procs in specified schema */
 			if (procform->pronamespace != namespaceId)
 				continue;
 		}
@@ -1003,7 +1023,16 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
 
 			foreach(nsp, activeSearchPath)
 			{
-				if (procform->pronamespace == lfirst_oid(nsp) &&
+				/* check if there is a module in the schema */
+				if (nspname)
+				{
+					moduleId = get_namespace_oid(nspname, lfirst_oid(nsp), true);
+					if (OidIsValid(moduleId))
+						if (procform->pronamespace == moduleId &&
+							procform->pronamespace != myTempNamespace)
+							break;
+				}
+				else if (procform->pronamespace == lfirst_oid(nsp) &&
 					procform->pronamespace != myTempNamespace)
 					break;
 				pathpos++;
@@ -1449,7 +1478,6 @@ FunctionIsVisible(Oid funcid)
 
 		clist = FuncnameGetCandidates(list_make1(makeString(proname)),
 									  nargs, NIL, false, false, false);
-
 		for (; clist; clist = clist->next)
 		{
 			if (memcmp(clist->args, procform->proargtypes.values,
@@ -1488,7 +1516,7 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
 	ListCell   *l;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, &opername);
+	DeconstructQualifiedName(names, &schemaname, NULL, &opername, false);
 
 	if (schemaname)
 	{
@@ -1595,7 +1623,7 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
 	int			i;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, &opername);
+	DeconstructQualifiedName(names, &schemaname, NULL, &opername, false);
 
 	if (schemaname)
 	{
@@ -2183,7 +2211,7 @@ get_statistics_object_oid(List *names, bool missing_ok)
 	ListCell   *l;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, &stats_name);
+	DeconstructQualifiedName(names, &schemaname, NULL, &stats_name, false);
 
 	if (schemaname)
 	{
@@ -2224,6 +2252,60 @@ get_statistics_object_oid(List *names, bool missing_ok)
 	return stats_oid;
 }
 
+/*
+ * get_module_oid - find a module by possibly qualified name
+ *
+ * If not found, returns InvalidOid if missing_ok, else throws error
+ */
+Oid
+get_module_oid(List *names, bool missing_ok)
+{
+	char	   *schemaname;
+	char	   *modulename;
+	Oid			namespaceId;
+	Oid			moduleId = InvalidOid;
+	ListCell   *l;
+
+	/* deconstruct the name list */
+	DeconstructQualifiedName(names, &schemaname, NULL, &modulename, false);
+
+	if (schemaname)
+	{
+		/* use exact schema given */
+		namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+		if (missing_ok && !OidIsValid(namespaceId))
+			moduleId = InvalidOid;
+		else
+			moduleId = GetSysCacheOid2(NAMESPACENAME, Anum_pg_namespace_oid,
+						  CStringGetDatum(modulename), ObjectIdGetDatum(namespaceId));
+	}
+	else
+	{
+		/* search for it in search path */
+		recomputeNamespacePath();
+
+		foreach(l, activeSearchPath)
+		{
+			namespaceId = lfirst_oid(l);
+
+			if (namespaceId == myTempNamespace)
+				continue;		/* do not look in temp namespace */
+			moduleId = GetSysCacheOid2(NAMESPACENAME, Anum_pg_namespace_oid,
+						  CStringGetDatum(modulename), ObjectIdGetDatum(namespaceId));
+			if (OidIsValid(moduleId))
+				break;
+		}
+	}
+
+	if (!OidIsValid(moduleId) && !missing_ok)
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("module \"%s\" does not exist",
+						NameListToString(names))));
+
+	return moduleId;
+}
+
 /*
  * StatisticsObjIsVisible
  *		Determine whether a statistics object (identified by OID) is visible in
@@ -2305,7 +2387,7 @@ get_ts_parser_oid(List *names, bool missing_ok)
 	ListCell   *l;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, &parser_name);
+	DeconstructQualifiedName(names, &schemaname, NULL, &parser_name, false);
 
 	if (schemaname)
 	{
@@ -2431,7 +2513,7 @@ get_ts_dict_oid(List *names, bool missing_ok)
 	ListCell   *l;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, &dict_name);
+	DeconstructQualifiedName(names, &schemaname, NULL, &dict_name, false);
 
 	if (schemaname)
 	{
@@ -2558,7 +2640,7 @@ get_ts_template_oid(List *names, bool missing_ok)
 	ListCell   *l;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, &template_name);
+	DeconstructQualifiedName(names, &schemaname, NULL, &template_name, false);
 
 	if (schemaname)
 	{
@@ -2684,7 +2766,7 @@ get_ts_config_oid(List *names, bool missing_ok)
 	ListCell   *l;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, &config_name);
+	DeconstructQualifiedName(names, &schemaname, NULL, &config_name, false);
 
 	if (schemaname)
 	{
@@ -2800,17 +2882,21 @@ TSConfigIsVisible(Oid cfgid)
 /*
  * DeconstructQualifiedName
  *		Given a possibly-qualified name expressed as a list of String nodes,
- *		extract the schema name and object name.
+ *		extract the schema name, module name and object name.
  *
  * *nspname_p is set to NULL if there is no explicit schema name.
+ * *modname_p is set to NULL if there is no explicit module name.
  */
 void
 DeconstructQualifiedName(List *names,
 						 char **nspname_p,
-						 char **objname_p)
+						 char **modname_p,
+						 char **objname_p,
+						 bool check_module)
 {
 	char	   *catalogname;
-	char	   *schemaname = NULL;
+	char	   *nspname = NULL;
+	char	   *modulename = NULL;
 	char	   *objname = NULL;
 
 	switch (list_length(names))
@@ -2819,22 +2905,70 @@ DeconstructQualifiedName(List *names,
 			objname = strVal(linitial(names));
 			break;
 		case 2:
-			schemaname = strVal(linitial(names));
+			nspname = strVal(linitial(names));
 			objname = strVal(lsecond(names));
 			break;
 		case 3:
-			catalogname = strVal(linitial(names));
-			schemaname = strVal(lsecond(names));
-			objname = strVal(lthird(names));
+			if (check_module)
+			{
+				/*
+				 * Since we don't allow cross-database references, check if the
+				 * first element is the current catalog and if is different assume
+				 * the first element is a schema
+				 */
+				if (strcmp(strVal(linitial(names)), get_database_name(MyDatabaseId)) != 0)
+				{
+					nspname = strVal(linitial(names));
+					modulename = strVal(lsecond(names));
+				}
+				else
+				{
+					catalogname = strVal(linitial(names));
+					nspname = strVal(lsecond(names));
+				}
 
-			/*
-			 * We check the catalog name and then ignore it.
-			 */
-			if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
+				objname = strVal(lthird(names));
+			}
+			else
+			{
+				catalogname = strVal(linitial(names));
+				nspname = strVal(lsecond(names));
+				objname = strVal(lthird(names));
+
+				/*
+				 * We check the catalog name and then ignore it.
+				 */
+				if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cross-database references are not implemented: %s",
+									NameListToString(names))));
+				}
+			break;
+		case 4:
+			if (check_module)
+			{
+				catalogname = strVal(linitial(names));
+				nspname = strVal(lsecond(names));
+				modulename = strVal(lthird(names));
+				objname = strVal(lfourth(names));
+
+				/*
+				 * We check the catalog name and then ignore it.
+				 */
+				if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cross-database references are not implemented: %s",
+									NameListToString(names))));
+			}
+			else
+			{
 				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cross-database references are not implemented: %s",
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("improper qualified name (too many dotted names): %s",
 								NameListToString(names))));
+			}
 			break;
 		default:
 			ereport(ERROR,
@@ -2844,7 +2978,9 @@ DeconstructQualifiedName(List *names,
 			break;
 	}
 
-	*nspname_p = schemaname;
+	*nspname_p = nspname;
+	if (modname_p)
+		*modname_p = modulename;
 	*objname_p = objname;
 }
 
@@ -2878,7 +3014,7 @@ LookupNamespaceNoError(const char *nspname)
 		return InvalidOid;
 	}
 
-	return get_namespace_oid(nspname, true);
+	return get_namespace_oid(nspname, InvalidOid, true);
 }
 
 /*
@@ -2907,7 +3043,7 @@ LookupExplicitNamespace(const char *nspname, bool missing_ok)
 		 */
 	}
 
-	namespaceId = get_namespace_oid(nspname, missing_ok);
+	namespaceId = get_namespace_oid(nspname, InvalidOid, missing_ok);
 	if (missing_ok && !OidIsValid(namespaceId))
 		return InvalidOid;
 
@@ -2945,7 +3081,7 @@ LookupCreationNamespace(const char *nspname)
 		return myTempNamespace;
 	}
 
-	namespaceId = get_namespace_oid(nspname, false);
+	namespaceId = get_namespace_oid(nspname, InvalidOid, false);
 
 	aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
@@ -2991,25 +3127,34 @@ CheckSetNamespace(Oid oldNspOid, Oid nspOid)
  * if we have to create or clean out the temp namespace.
  */
 Oid
-QualifiedNameGetCreationNamespace(List *names, char **objname_p)
+QualifiedNameGetCreationNamespace(List *names, char **objname_p, bool check_module)
 {
-	char	   *schemaname;
+	char	   *nspname = NULL;
+	char	   *modulename = NULL;
+	Oid			nspparent;
 	Oid			namespaceId;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(names, &schemaname, objname_p);
+	DeconstructQualifiedName(names, &nspname, &modulename, objname_p, check_module);
 
-	if (schemaname)
+	if (nspname && modulename)
+	{
+		/* use exact schema given */
+		nspparent = LookupExplicitNamespace(nspname, false);
+
+		namespaceId = get_namespace_oid(modulename, nspparent, false);
+	}
+	else if (nspname)
 	{
 		/* check for pg_temp alias */
-		if (strcmp(schemaname, "pg_temp") == 0)
+		if (strcmp(nspname, "pg_temp") == 0)
 		{
 			/* Initialize temp namespace */
 			AccessTempTableNamespace(false);
 			return myTempNamespace;
 		}
 		/* use exact schema given */
-		namespaceId = get_namespace_oid(schemaname, false);
+		namespaceId = get_namespace_oid(nspname, InvalidOid, false);
 		/* we do not check for USAGE rights here! */
 	}
 	else
@@ -3039,12 +3184,12 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
  * true, just return InvalidOid.
  */
 Oid
-get_namespace_oid(const char *nspname, bool missing_ok)
+get_namespace_oid(const char *nspname, Oid nspnamespace, bool missing_ok)
 {
 	Oid			oid;
 
-	oid = GetSysCacheOid1(NAMESPACENAME, Anum_pg_namespace_oid,
-						  CStringGetDatum(nspname));
+	oid = GetSysCacheOid2(NAMESPACENAME, Anum_pg_namespace_oid,
+						  CStringGetDatum(nspname), ObjectIdGetDatum(nspnamespace));
 	if (!OidIsValid(oid) && !missing_ok)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_SCHEMA),
@@ -3607,7 +3752,7 @@ get_collation_oid(List *name, bool missing_ok)
 	ListCell   *l;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(name, &schemaname, &collation_name);
+	DeconstructQualifiedName(name, &schemaname, NULL, &collation_name, false);
 
 	if (schemaname)
 	{
@@ -3660,7 +3805,7 @@ get_conversion_oid(List *name, bool missing_ok)
 	ListCell   *l;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(name, &schemaname, &conversion_name);
+	DeconstructQualifiedName(name, &schemaname, NULL, &conversion_name, false);
 
 	if (schemaname)
 	{
@@ -3789,7 +3934,7 @@ recomputeNamespacePath(void)
 				char	   *rname;
 
 				rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
-				namespaceId = get_namespace_oid(rname, true);
+				namespaceId = get_namespace_oid(rname, InvalidOid, true);
 				ReleaseSysCache(tuple);
 				if (OidIsValid(namespaceId) &&
 					!list_member_oid(oidlist, namespaceId) &&
@@ -3818,7 +3963,7 @@ recomputeNamespacePath(void)
 		else
 		{
 			/* normal namespace reference */
-			namespaceId = get_namespace_oid(curname, true);
+			namespaceId = get_namespace_oid(curname, InvalidOid, true);
 			if (OidIsValid(namespaceId) &&
 				!list_member_oid(oidlist, namespaceId) &&
 				pg_namespace_aclcheck(namespaceId, roleid,
@@ -3987,7 +4132,7 @@ InitTempTableNamespace(void)
 
 	snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
 
-	namespaceId = get_namespace_oid(namespaceName, true);
+	namespaceId = get_namespace_oid(namespaceName, InvalidOid, true);
 	if (!OidIsValid(namespaceId))
 	{
 		/*
@@ -3998,8 +4143,8 @@ InitTempTableNamespace(void)
 		 * temp tables.  This works because the places that access the temp
 		 * namespace for my own backend skip permissions checks on it.
 		 */
-		namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
-									  true);
+		namespaceId = NamespaceCreate(namespaceName, InvalidOid, NSPKIND_SCHEMA,
+									  BOOTSTRAP_SUPERUSERID, true);
 		/* Advance command counter to make namespace visible */
 		CommandCounterIncrement();
 	}
@@ -4020,11 +4165,11 @@ InitTempTableNamespace(void)
 	snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d",
 			 MyBackendId);
 
-	toastspaceId = get_namespace_oid(namespaceName, true);
+	toastspaceId = get_namespace_oid(namespaceName, InvalidOid, true);
 	if (!OidIsValid(toastspaceId))
 	{
-		toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
-									   true);
+		toastspaceId = NamespaceCreate(namespaceName, InvalidOid, NSPKIND_SCHEMA,
+									   BOOTSTRAP_SUPERUSERID, true);
 		/* Advance command counter to make namespace visible */
 		CommandCounterIncrement();
 	}
unchanged:
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -406,12 +406,26 @@ static const ObjectPropertyType ObjectProperty[] =
 		NAMESPACENAME,
 		Anum_pg_namespace_oid,
 		Anum_pg_namespace_nspname,
-		InvalidAttrNumber,
+		Anum_pg_namespace_nspnamespace,
 		Anum_pg_namespace_nspowner,
 		Anum_pg_namespace_nspacl,
 		OBJECT_SCHEMA,
 		true
 	},
+	{
+		"module",
+		NamespaceRelationId,
+		NamespaceOidIndexId,
+		NAMESPACEOID,
+		NAMESPACENAME,
+		Anum_pg_namespace_oid,
+		Anum_pg_namespace_nspname,
+		Anum_pg_namespace_nspnamespace,
+		Anum_pg_namespace_nspowner,
+		Anum_pg_namespace_nspacl,
+		OBJECT_MODULE,
+		true
+	},
 	{
 		"relation",
 		RelationRelationId,
@@ -765,6 +779,10 @@ static const struct object_type_map
 	{
 		"schema", OBJECT_SCHEMA
 	},
+	/* OCLASS_MODULE */
+	{
+		"module", OBJECT_MODULE
+	},
 	/* OCLASS_TSPARSER */
 	{
 		"text search parser", OBJECT_TSPARSER
@@ -1128,6 +1146,12 @@ get_object_address(ObjectType objtype, Node *object,
 															 missing_ok);
 				address.objectSubId = 0;
 				break;
+			case OBJECT_MODULE:
+				address.classId = NamespaceRelationId;
+				address.objectId = get_module_oid(castNode(List, object),
+														   missing_ok);
+				address.objectSubId = 0;
+				break;
 			default:
 				elog(ERROR, "unrecognized objtype: %d", (int) objtype);
 				/* placate compiler, in case it thinks elog might return */
@@ -1281,7 +1305,7 @@ get_object_address_unqualified(ObjectType objtype,
 			break;
 		case OBJECT_SCHEMA:
 			address.classId = NamespaceRelationId;
-			address.objectId = get_namespace_oid(name, missing_ok);
+			address.objectId = get_namespace_oid(name, InvalidOid, missing_ok);
 			address.objectSubId = 0;
 			break;
 		case OBJECT_LANGUAGE:
@@ -2013,7 +2037,7 @@ get_object_address_defacl(List *object, bool missing_ok)
 	 */
 	if (schema)
 	{
-		schemaid = get_namespace_oid(schema, true);
+		schemaid = get_namespace_oid(schema, InvalidOid, true);
 		if (schemaid == InvalidOid)
 			goto not_found;
 	}
@@ -2267,6 +2291,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 		case OBJECT_TABCONSTRAINT:
 		case OBJECT_OPCLASS:
 		case OBJECT_OPFAMILY:
+		case OBJECT_MODULE:
 			objnode = (Node *) name;
 			break;
 		case OBJECT_ACCESS_METHOD:
@@ -2431,6 +2456,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
 							   NameListToString((castNode(ObjectWithArgs, object))->objname));
 			break;
 		case OBJECT_SCHEMA:
+		case OBJECT_MODULE:
 			if (!pg_namespace_ownercheck(address.objectId, roleid))
 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
 							   strVal((Value *) object));
unchanged:
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -40,7 +40,8 @@
  * ---------------
  */
 Oid
-NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
+NamespaceCreate(const char *nspName, Oid nspnamespace, char nspkind,
+				Oid ownerId, bool isTemp)
 {
 	Relation	nspdesc;
 	HeapTuple	tup;
@@ -58,7 +59,7 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
 		elog(ERROR, "no namespace name supplied");
 
 	/* make sure there is no existing namespace of same name */
-	if (SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(nspName)))
+	if (SearchSysCacheExists2(NAMESPACENAME, PointerGetDatum(nspName), nspnamespace))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_SCHEMA),
 				 errmsg("schema \"%s\" already exists", nspName)));
@@ -85,6 +86,8 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
 	namestrcpy(&nname, nspName);
 	values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
 	values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
+	values[Anum_pg_namespace_nspnamespace - 1] = ObjectIdGetDatum(nspnamespace);
+	values[Anum_pg_namespace_nspkind - 1] = CharGetDatum(nspkind);
 	if (nspacl != NULL)
 		values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl);
 	else
unchanged:
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1460,7 +1460,7 @@ CreateExtensionInternal(char *extensionName,
 	if (schemaName)
 	{
 		/* If the user is giving us the schema name, it must exist already. */
-		schemaOid = get_namespace_oid(schemaName, false);
+		schemaOid = get_namespace_oid(schemaName, InvalidOid, false);
 	}
 
 	if (control->schema != NULL)
@@ -1484,7 +1484,7 @@ CreateExtensionInternal(char *extensionName,
 		schemaName = control->schema;
 
 		/* Find or create the schema in case it does not exist. */
-		schemaOid = get_namespace_oid(schemaName, true);
+		schemaOid = get_namespace_oid(schemaName, InvalidOid, true);
 
 		if (!OidIsValid(schemaOid))
 		{
@@ -1501,7 +1501,7 @@ CreateExtensionInternal(char *extensionName,
 			 * CreateSchemaCommand includes CommandCounterIncrement, so new
 			 * schema is now visible.
 			 */
-			schemaOid = get_namespace_oid(schemaName, false);
+			schemaOid = get_namespace_oid(schemaName, InvalidOid, false);
 		}
 	}
 	else if (!OidIsValid(schemaOid))
unchanged:
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -113,7 +113,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString,
 	 * creation-permission check first, we do likewise.
 	 */
 	if (stmt->if_not_exists &&
-		SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(schemaName)))
+		SearchSysCacheExists2(NAMESPACENAME, PointerGetDatum(schemaName), InvalidOid))
 	{
 		ereport(NOTICE,
 				(errcode(ERRCODE_DUPLICATE_SCHEMA),
@@ -135,7 +135,8 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString,
 							   save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
 
 	/* Create the schema's namespace */
-	namespaceId = NamespaceCreate(schemaName, owner_uid, false);
+	namespaceId = NamespaceCreate(schemaName, InvalidOid, NSPKIND_SCHEMA,
+								  owner_uid, false);
 
 	/* Advance cmd counter to make the namespace visible */
 	CommandCounterIncrement();
@@ -226,7 +227,7 @@ RenameSchema(const char *oldname, const char *newname)
 
 	rel = table_open(NamespaceRelationId, RowExclusiveLock);
 
-	tup = SearchSysCacheCopy1(NAMESPACENAME, CStringGetDatum(oldname));
+	tup = SearchSysCacheCopy2(NAMESPACENAME, CStringGetDatum(oldname), InvalidOid);
 	if (!HeapTupleIsValid(tup))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_SCHEMA),
@@ -236,7 +237,7 @@ RenameSchema(const char *oldname, const char *newname)
 	nspOid = nspform->oid;
 
 	/* make sure the new name doesn't exist */
-	if (OidIsValid(get_namespace_oid(newname, true)))
+	if (OidIsValid(get_namespace_oid(newname, InvalidOid, true)))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_SCHEMA),
 				 errmsg("schema \"%s\" already exists", newname)));
@@ -306,7 +307,7 @@ AlterSchemaOwner(const char *name, Oid newOwnerId)
 
 	rel = table_open(NamespaceRelationId, RowExclusiveLock);
 
-	tup = SearchSysCache1(NAMESPACENAME, CStringGetDatum(name));
+	tup = SearchSysCache2(NAMESPACENAME, CStringGetDatum(name), InvalidOid);
 	if (!HeapTupleIsValid(tup))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_SCHEMA),
unchanged:
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -3827,7 +3827,7 @@ convert_schema_name(text *schemaname)
 {
 	char	   *nspname = text_to_cstring(schemaname);
 
-	return get_namespace_oid(nspname, false);
+	return get_namespace_oid(nspname, InvalidOid, false);
 }
 
 /*
unchanged:
--- a/src/backend/utils/adt/pg_upgrade_support.c
+++ b/src/backend/utils/adt/pg_upgrade_support.c
@@ -184,7 +184,7 @@ binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS)
 
 	InsertExtensionTuple(text_to_cstring(extName),
 						 GetUserId(),
-						 get_namespace_oid(text_to_cstring(schemaName), false),
+						 get_namespace_oid(text_to_cstring(schemaName), InvalidOid, false),
 						 relocatable,
 						 text_to_cstring(extVersion),
 						 extConfig,
unchanged:
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -1762,7 +1762,7 @@ regnamespacein(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_INVALID_NAME),
 				 errmsg("invalid name syntax")));
 
-	result = get_namespace_oid(strVal(linitial(names)), false);
+	result = get_namespace_oid(strVal(linitial(names)), InvalidOid, false);
 
 	PG_RETURN_OID(result);
 }
@@ -1786,7 +1786,7 @@ to_regnamespace(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_INVALID_NAME),
 				 errmsg("invalid name syntax")));
 
-	result = get_namespace_oid(strVal(linitial(names)), true);
+	result = get_namespace_oid(strVal(linitial(names)), InvalidOid, true);
 
 	if (OidIsValid(result))
 		PG_RETURN_OID(result);
unchanged:
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -509,10 +509,10 @@ static const struct cachedesc cacheinfo[] = {
 	},
 	{NamespaceRelationId,		/* NAMESPACENAME */
 		NamespaceNameIndexId,
-		1,
+		2,
 		{
 			Anum_pg_namespace_nspname,
-			0,
+			Anum_pg_namespace_nspnamespace,
 			0,
 			0
 		},
only in patch2:
unchanged:
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -135,15 +135,18 @@ extern Oid	get_ts_config_oid(List *names, bool missing_ok);
 extern bool TSConfigIsVisible(Oid cfgid);
 
 extern void DeconstructQualifiedName(List *names,
-									 char **nspname_p,
-									 char **objname_p);
+											char **nspname_p,
+											char **modname_p,
+											char **objname_p,
+											bool check_module);
 extern Oid	LookupNamespaceNoError(const char *nspname);
 extern Oid	LookupExplicitNamespace(const char *nspname, bool missing_ok);
-extern Oid	get_namespace_oid(const char *nspname, bool missing_ok);
+extern Oid	get_namespace_oid(const char *nspname, Oid nspnamespace, bool missing_ok);
+extern Oid	get_module_oid(List *names, bool missing_ok);
 
 extern Oid	LookupCreationNamespace(const char *nspname);
 extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid);
-extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
+extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p, bool check_module);
 extern RangeVar *makeRangeVarFromNameList(List *names);
 extern char *NameListToString(List *names);
 extern char *NameListToQuotedString(List *names);
only in patch2:
unchanged:
--- a/src/include/catalog/pg_namespace.dat
+++ b/src/include/catalog/pg_namespace.dat
@@ -14,12 +14,15 @@
 
 { oid => '11', oid_symbol => 'PG_CATALOG_NAMESPACE',
   descr => 'system catalog schema',
-  nspname => 'pg_catalog', nspacl => '_null_' },
+  nspname => 'pg_catalog', nspnamespace => '0',
+  nspkind => 's', nspacl => '_null_' },
 { oid => '99', oid_symbol => 'PG_TOAST_NAMESPACE',
   descr => 'reserved schema for TOAST tables',
-  nspname => 'pg_toast', nspacl => '_null_' },
+  nspname => 'pg_toast', nspnamespace => '0',
+  nspkind => 's', nspacl => '_null_' },
 { oid => '2200', oid_symbol => 'PG_PUBLIC_NAMESPACE',
   descr => 'standard public schema',
-  nspname => 'public', nspacl => '_null_' },
+  nspname => 'public', nspnamespace => '0',
+  nspkind => 's', nspacl => '_null_' },
 
 ]
only in patch2:
unchanged:
--- a/src/include/catalog/pg_namespace.h
+++ b/src/include/catalog/pg_namespace.h
@@ -29,6 +29,8 @@
  *
  *	nspname				name of the namespace
  *	nspowner			owner (creator) of the namespace
+ *	nspnamespace		parent of the namespace
+ *	nspkind				the type namespace
  *	nspacl				access privilege list
  * ----------------------------------------------------------------
  */
@@ -38,6 +40,9 @@ CATALOG(pg_namespace,2615,NamespaceRelationId)
 
 	NameData	nspname;
 	Oid			nspowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);
+	Oid			nspnamespace BKI_DEFAULT(0);
+	char		nspkind BKI_DEFAULT(s);
+
 
 #ifdef CATALOG_VARLEN			/* variable-length fields start here */
 	aclitem		nspacl[1];
@@ -53,14 +58,18 @@ typedef FormData_pg_namespace *Form_pg_namespace;
 
 DECLARE_TOAST(pg_namespace, 4163, 4164);
 
-DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btree(nspname name_ops));
+DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, on pg_namespace using btree(nspname name_ops, nspnamespace oid_ops));
 #define NamespaceNameIndexId  2684
 DECLARE_UNIQUE_INDEX_PKEY(pg_namespace_oid_index, 2685, on pg_namespace using btree(oid oid_ops));
 #define NamespaceOidIndexId  2685
 
+#define		NSPKIND_SCHEMA			's'		/* schema */
+#define		NSPKIND_MODULE			'm'		/* module */
+
 /*
  * prototypes for functions in pg_namespace.c
  */
-extern Oid	NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp);
+extern Oid	NamespaceCreate(const char *nspName, Oid nspnamespace, char nspkind,
+							Oid ownerId, bool isTemp);
 
 #endif							/* PG_NAMESPACE_H */
