unchanged:
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -604,7 +604,8 @@ get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
 	}
 
 	otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
-													   &otherName);
+													   &otherName,
+													   false);
 
 	if (strcmp(otherName, operatorName) == 0 &&
 		otherNamespace == operatorNamespace &&
unchanged:
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -101,7 +101,7 @@ DefineAggregate(ParseState *pstate,
 	ListCell   *pl;
 
 	/* Convert list of names to a name and namespace */
-	aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
+	aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
unchanged:
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -384,6 +384,7 @@ ExecRenameStmt(RenameStmt *stmt)
 		case OBJECT_OPCLASS:
 		case OBJECT_OPFAMILY:
 		case OBJECT_LANGUAGE:
+		case OBJECT_MODULE:
 		case OBJECT_PROCEDURE:
 		case OBJECT_ROUTINE:
 		case OBJECT_STATISTIC_EXT:
unchanged:
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -73,7 +73,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
 	Oid			newoid;
 	ObjectAddress address;
 
-	collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
+	collNamespace = QualifiedNameGetCreationNamespace(names, &collName, false);
 
 	aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
unchanged:
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -51,7 +51,7 @@ CreateConversionCommand(CreateConversionStmt *stmt)
 
 	/* Convert list of names to a name and namespace */
 	namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name,
-													&conversion_name);
+													&conversion_name, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
unchanged:
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -967,6 +967,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
 		case OBJECT_LANGUAGE:
 		case OBJECT_LARGEOBJECT:
 		case OBJECT_MATVIEW:
+		case OBJECT_MODULE:
 		case OBJECT_OPCLASS:
 		case OBJECT_OPERATOR:
 		case OBJECT_OPFAMILY:
@@ -2087,6 +2088,8 @@ stringify_grant_objtype(ObjectType objtype)
 			return "LANGUAGE";
 		case OBJECT_LARGEOBJECT:
 			return "LARGE OBJECT";
+		case OBJECT_MODULE:
+			return "MODULE";
 		case OBJECT_SCHEMA:
 			return "SCHEMA";
 		case OBJECT_PROCEDURE:
@@ -2169,6 +2172,8 @@ stringify_adefprivs_objtype(ObjectType objtype)
 			return "LANGUAGES";
 		case OBJECT_LARGEOBJECT:
 			return "LARGE OBJECTS";
+		case OBJECT_MODULE:
+			return "MODULES";
 		case OBJECT_SCHEMA:
 			return "SCHEMAS";
 		case OBJECT_PROCEDURE:
unchanged:
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -148,7 +148,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
 				 errmsg("type \"%s\" is not yet defined", typnam),
 				 errdetail("Creating a shell type definition.")));
 		namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
-														&typname);
+														&typname, false);
 		aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
 										  ACL_CREATE);
 		if (aclresult != ACLCHECK_OK)
@@ -1050,7 +1050,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
 
 	/* Convert list of names to a name and namespace */
 	namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
-													&funcname);
+													&funcname, true);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
unchanged:
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2039,7 +2039,7 @@ ResolveOpClass(List *opclass, Oid attrType,
 	 */
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(opclass, &schemaname, &opcname);
+	DeconstructQualifiedName(opclass, &schemaname, NULL, &opcname, false);
 
 	if (schemaname)
 	{
@@ -2787,7 +2787,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
 	 */
 	if (objectKind == REINDEX_OBJECT_SCHEMA)
 	{
-		objectOid = get_namespace_oid(objectName, false);
+		objectOid = get_namespace_oid(objectName, InvalidOid, false);
 
 		if (!pg_namespace_ownercheck(objectOid, GetUserId()))
 			aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA,
unchanged:
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -85,7 +85,7 @@ OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
 	HeapTuple	htup;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
+	DeconstructQualifiedName(opfamilyname, &schemaname, NULL, &opfname, false);
 
 	if (schemaname)
 	{
@@ -166,7 +166,7 @@ OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
 	HeapTuple	htup;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(opclassname, &schemaname, &opcname);
+	DeconstructQualifiedName(opclassname, &schemaname, NULL, &opcname, false);
 
 	if (schemaname)
 	{
@@ -354,7 +354,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
-													 &opcname);
+													 &opcname, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
@@ -769,7 +769,7 @@ DefineOpFamily(CreateOpFamilyStmt *stmt)
 
 	/* Convert list of names to a name and namespace */
 	namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
-													 &opfname);
+													 &opfname, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
unchanged:
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -87,7 +87,7 @@ DefineOperator(List *names, List *parameters)
 	ListCell   *pl;
 
 	/* Convert list of names to a name and namespace */
-	oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
+	oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
unchanged:
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -48,6 +48,7 @@ SecLabelSupportsObjectType(ObjectType objtype)
 		case OBJECT_LANGUAGE:
 		case OBJECT_LARGEOBJECT:
 		case OBJECT_MATVIEW:
+		case OBJECT_MODULE:
 		case OBJECT_PROCEDURE:
 		case OBJECT_PUBLICATION:
 		case OBJECT_ROLE:
unchanged:
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -163,7 +163,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 	 */
 	if (stmt->defnames)
 		namespaceId = QualifiedNameGetCreationNamespace(stmt->defnames,
-														&namestr);
+														&namestr, false);
 	else
 	{
 		namespaceId = RelationGetNamespace(rel);
@@ -630,7 +630,7 @@ AlterStatistics(AlterStatsStmt *stmt)
 
 		Assert(stmt->missing_ok);
 
-		DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
+		DeconstructQualifiedName(stmt->defnames, &schemaname, NULL, &statname, false);
 
 		if (schemaname)
 			ereport(NOTICE,
unchanged:
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -196,7 +196,7 @@ DefineTSParser(List *names, List *parameters)
 	prsRel = table_open(TSParserRelationId, RowExclusiveLock);
 
 	/* Convert list of names to a name and namespace */
-	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
+	namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname, false);
 
 	/* initialize tuple fields with name/namespace */
 	memset(values, 0, sizeof(values));
@@ -405,7 +405,7 @@ DefineTSDictionary(List *names, List *parameters)
 	ObjectAddress address;
 
 	/* Convert list of names to a name and namespace */
-	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
+	namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
@@ -701,7 +701,7 @@ DefineTSTemplate(List *names, List *parameters)
 				 errmsg("must be superuser to create text search templates")));
 
 	/* Convert list of names to a name and namespace */
-	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
+	namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname, false);
 
 	tmplRel = table_open(TSTemplateRelationId, RowExclusiveLock);
 
@@ -908,7 +908,7 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
 	ObjectAddress address;
 
 	/* Convert list of names to a name and namespace */
-	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
+	namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
unchanged:
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -217,7 +217,7 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 				 errmsg("must be superuser to create a base type")));
 
 	/* Convert list of names to a name and namespace */
-	typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
+	typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName, false);
 
 #ifdef NOT_USED
 	/* XXX this is unnecessary given the superuser check above */
@@ -733,7 +733,7 @@ DefineDomain(CreateDomainStmt *stmt)
 
 	/* Convert list of names to a name and namespace */
 	domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
-														&domainName);
+														&domainName, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
@@ -1149,7 +1149,7 @@ DefineEnum(CreateEnumStmt *stmt)
 
 	/* Convert list of names to a name and namespace */
 	enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
-													  &enumName);
+													  &enumName, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
@@ -1369,7 +1369,7 @@ DefineRange(CreateRangeStmt *stmt)
 
 	/* Convert list of names to a name and namespace */
 	typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
-													  &typeName);
+													  &typeName, false);
 
 	/* Check we have creation rights in target namespace */
 	aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
@@ -1457,7 +1457,7 @@ DefineRange(CreateRangeStmt *stmt)
 						 errmsg("conflicting or redundant options")));
 			/* we can look up the subtype name immediately */
 			multirangeNamespace = QualifiedNameGetCreationNamespace(defGetQualifiedName(defel),
-																	&multirangeTypeName);
+																	&multirangeTypeName, false);
 		}
 		else
 			ereport(ERROR,
unchanged:
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -262,7 +262,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	struct GroupClause  *groupclause;
 }
 
-%type <node>	stmt toplevel_stmt schema_stmt routine_body_stmt
+%type <node>	stmt toplevel_stmt schema_stmt routine_body_stmt module_stmt
 		AlterEventTrigStmt AlterCollationStmt
 		AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
 		AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
@@ -301,6 +301,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 		CreateMatViewStmt RefreshMatViewStmt CreateAmStmt
 		CreatePublicationStmt AlterPublicationStmt
 		CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt
+		CreateModuleStmt
 
 %type <node>	select_no_parens select_with_parens select_clause
 				simple_select values_clause
@@ -344,7 +345,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <str>		opt_in_database
 
 %type <str>		OptSchemaName
-%type <list>	OptSchemaEltList
+%type <list>	OptSchemaEltList OptModuleEltList
 
 %type <chr>		am_type
 
@@ -368,7 +369,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %type <list>	func_name handler_name qual_Op qual_all_Op subquery_Op
 				opt_class opt_inline_handler opt_validator validator_clause
-				opt_collate
+				opt_collate module_name
 
 %type <range>	qualified_name insert_target OptConstrFromTable
 
@@ -681,7 +682,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL
 	LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED
 
-	MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE
+	MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MODULE
+	MONTH_P MOVE
 
 	NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NFC NFD NFKC NFKD NO NONE
 	NORMALIZE NORMALIZED
@@ -954,6 +956,7 @@ stmt:
 			| CreateFunctionStmt
 			| CreateGroupStmt
 			| CreateMatViewStmt
+			| CreateModuleStmt
 			| CreateOpClassStmt
 			| CreateOpFamilyStmt
 			| CreatePublicationStmt
@@ -1466,6 +1469,84 @@ schema_stmt:
 			| ViewStmt
 		;
 
+/*****************************************************************************
+ *
+ * Manipulate a module
+ *
+ *****************************************************************************/
+
+CreateModuleStmt:
+			CREATE MODULE module_name OptModuleEltList
+				{
+					CreateModuleStmt *n = makeNode(CreateModuleStmt);
+					n->modulename = $3;
+					n->authrole = NULL;
+					n->moduleElts = $4;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE MODULE module_name OWNER RoleSpec OptModuleEltList
+				{
+					CreateModuleStmt *n = makeNode(CreateModuleStmt);
+					n->modulename = $3;
+					n->authrole = $5;
+					n->moduleElts = $6;
+					n->if_not_exists = false;
+					$$ = (Node *)n;
+				}
+			| CREATE MODULE IF_P NOT EXISTS module_name OptModuleEltList
+				{
+					CreateModuleStmt *n = makeNode(CreateModuleStmt);
+					n->modulename = $6;
+					n->authrole = NULL;
+					if ($7 != NIL)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("CREATE MODULE IF NOT EXISTS cannot include module elements"),
+								 parser_errposition(@7)));
+					n->moduleElts = $7;
+					n->if_not_exists = true;
+					$$ = (Node *)n;
+				}
+			| CREATE MODULE IF_P NOT EXISTS module_name OWNER RoleSpec OptModuleEltList
+				{
+					CreateModuleStmt *n = makeNode(CreateModuleStmt);
+					n->modulename = $6;
+					n->authrole = $8;
+					if ($9 != NIL)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("CREATE MODULE IF NOT EXISTS cannot include module elements"),
+								 parser_errposition(@9)));
+					n->moduleElts = $9;
+					n->if_not_exists = true;
+					$$ = (Node *)n;
+				}
+		;
+
+module_name:
+			name						{ $$ = list_make1(makeString($1)); }
+			| name attrs				{ $$ = lcons(makeString($1), $2); }
+		;
+
+OptModuleEltList:
+			OptModuleEltList module_stmt
+				{
+					if (@$ < 0)			/* see comments for YYLLOC_DEFAULT */
+						@$ = @2;
+					$$ = lappend($1, $2);
+				}
+			| /* EMPTY */
+				{ $$ = NIL; }
+		;
+
+/*
+ *	module_stmt are the ones that can show up inside a CREATE MODULE statement.
+ */
+module_stmt:
+			CreateFunctionStmt
+			;
+
 
 /*****************************************************************************
  *
@@ -6308,6 +6389,26 @@ DropStmt:	DROP object_type_any_name IF_P EXISTS any_name_list opt_drop_behavior
 					n->concurrent = true;
 					$$ = (Node *)n;
 				}
+			| DROP MODULE any_name_list opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_MODULE;
+					n->objects = $3;
+					n->behavior = $4;
+					n->missing_ok = false;
+					n->concurrent = false;
+					$$ = (Node *)n;
+				}
+			| DROP MODULE IF_P EXISTS any_name_list opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_MODULE;
+					n->objects = $5;
+					n->behavior = $6;
+					n->missing_ok = true;
+					n->concurrent = false;
+					$$ = (Node *)n;
+				}
 		;
 
 /* object types taking any_name/any_name_list */
@@ -8569,6 +8670,15 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
+			| ALTER MODULE module_name RENAME TO name
+				{
+					RenameStmt *n = makeNode(RenameStmt);
+					n->renameType = OBJECT_MODULE;
+					n->object = (Node *) $3;
+					n->newname = $6;
+					n->missing_ok = false;
+					$$ = (Node *)n;
+				}
 			| ALTER opt_procedural LANGUAGE name RENAME TO name
 				{
 					RenameStmt *n = makeNode(RenameStmt);
@@ -15639,6 +15749,7 @@ unreserved_keyword:
 			| MINUTE_P
 			| MINVALUE
 			| MODE
+			| MODULE
 			| MONTH_P
 			| MOVE
 			| NAME_P
@@ -16205,6 +16316,7 @@ bare_label_keyword:
 			| METHOD
 			| MINVALUE
 			| MODE
+			| MODULE
 			| MOVE
 			| NAME_P
 			| NAMES
unchanged:
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -18,8 +18,10 @@
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "commands/dbcommands.h"
 #include "funcapi.h"
 #include "lib/stringinfo.h"
+#include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/parse_agg.h"
@@ -1421,7 +1423,6 @@ func_get_detail(List *funcname,
 	raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
 										   expand_variadic, expand_defaults,
 										   false);
-
 	/*
 	 * Quickly check if there is an exact match to the input datatypes (there
 	 * can be only one)
@@ -1549,7 +1550,6 @@ func_get_detail(List *funcname,
 			/* one match only? then run with it... */
 			if (ncandidates == 1)
 				best_candidate = current_candidates;
-
 			/*
 			 * multiple candidates? then better decide or throw an error...
 			 */
@@ -1882,6 +1882,16 @@ FuncNameAsType(List *funcname)
 	Oid			result;
 	Type		typtup;
 
+	/*
+	 * check if this may be in a module. If it could be, don't check if it
+	 * may be a type since they can not be in a module
+	 */
+	if (list_length(funcname) == 3)
+	{
+		if (strcmp(strVal(linitial(funcname)), get_database_name(MyDatabaseId)) != 0)
+			return InvalidOid;
+	}
+
 	/*
 	 * temp_ok=false protects the <refsect1 id="sql-createfunction-security">
 	 * contract for writing SECURITY DEFINER functions safely.
@@ -2058,7 +2068,6 @@ LookupFuncNameInternal(List *funcname, int nargs, const Oid *argtypes,
 
 	clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false,
 								  missing_ok);
-
 	/*
 	 * If no arguments were specified, the name must yield a unique candidate.
 	 */
unchanged:
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -954,7 +954,7 @@ make_oper_cache_key(ParseState *pstate, OprCacheKey *key, List *opname,
 	char	   *opername;
 
 	/* deconstruct the name list */
-	DeconstructQualifiedName(opname, &schemaname, &opername);
+	DeconstructQualifiedName(opname, &schemaname, NULL, &opername, false);
 
 	/* ensure zero-fill for stable hashing */
 	MemSet(key, 0, sizeof(OprCacheKey));
unchanged:
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -166,7 +166,7 @@ LookupTypeNameExtended(ParseState *pstate,
 		char	   *typname;
 
 		/* deconstruct the name list */
-		DeconstructQualifiedName(typeName->names, &schemaname, &typname);
+		DeconstructQualifiedName(typeName->names, &schemaname, NULL, &typname, false);
 
 		if (schemaname)
 		{
unchanged:
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -113,6 +113,14 @@ typedef struct
 	List	   *grants;			/* GRANT items */
 } CreateSchemaStmtContext;
 
+/* State shared by transformCreateModuleStmt and its subroutines */
+typedef struct
+{
+	const char *stmtType;		/* "CREATE MODULE" or "ALTER MODULE" */
+	List	   *modulename;		/* name of module */
+	RoleSpec   *authrole;		/* owner of module */
+	List	   *functions;		/* CREATE FUNCTION items */
+} CreateModuleStmtContext;
 
 static void transformColumnDefinition(CreateStmtContext *cxt,
 									  ColumnDef *column);
@@ -3944,6 +3952,70 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
 	return result;
 }
 
+/*
+ * transformCreateModuleStmt -
+ *	  analyzes the CREATE MODULE statement
+ *
+ * Split the module element list into individual commands and place
+ * them in the result list in an order such that there are no forward
+ * references. Currently there are only functions allowed in modules
+ * but the spec allows variables and temp tables so this provides a
+ * way to have them created before the functions that could use them.
+ *
+ * The functions are also checked to make sure there is not an explicit
+ * namespace attempted to be used.
+ */
+List *
+transformCreateModuleStmt(CreateModuleStmt *stmt)
+{
+	CreateModuleStmtContext cxt;
+	List	   *result;
+	ListCell   *elements;
+
+
+	cxt.stmtType = "CREATE MODULE";
+	cxt.modulename = stmt->modulename;
+	cxt.authrole = (RoleSpec *) stmt->authrole;
+	cxt.functions = NIL;
+
+	/*
+	 * Run through each module element in the module element list. Separate
+	 * statements by type, and do preliminary analysis.
+	 */
+	foreach(elements, stmt->moduleElts)
+	{
+		Node	   *element = lfirst(elements);
+
+		switch (nodeTag(element))
+		{
+			case T_CreateFunctionStmt:
+				{
+					CreateFunctionStmt *elp = (CreateFunctionStmt *) element;
+
+					if (list_length(elp->funcname) > 1)
+						ereport(ERROR,
+								(errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
+								 errmsg("CREATE FUNCTION (%s) specifies a "
+										"namespace inside of CREATE MODULE (%s)",
+										NameListToString(elp->funcname),
+										NameListToString(cxt.modulename))));
+
+					cxt.functions = lappend(cxt.functions, element);
+				}
+				break;
+
+			default:
+				elog(ERROR, "unrecognized node type: %d",
+					 (int) nodeTag(element));
+		}
+	}
+
+	result = NIL;
+	result = list_concat(result, cxt.functions);
+
+	return result;
+}
+
 /*
  * setSchemaName
  *		Set or check schema name in an element of a CREATE SCHEMA command
unchanged:
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -42,6 +42,7 @@
 #include "commands/extension.h"
 #include "commands/lockcmds.h"
 #include "commands/matview.h"
+#include "commands/modulecmds.h"
 #include "commands/policy.h"
 #include "commands/portalcmds.h"
 #include "commands/prepare.h"
@@ -178,6 +179,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree)
 		case T_CreateForeignServerStmt:
 		case T_CreateForeignTableStmt:
 		case T_CreateFunctionStmt:
+		case T_CreateModuleStmt:
 		case T_CreateOpClassStmt:
 		case T_CreateOpFamilyStmt:
 		case T_CreatePLangStmt:
@@ -1097,6 +1099,19 @@ ProcessUtilitySlow(ParseState *pstate,
 				commandCollected = true;
 				break;
 
+			case T_CreateModuleStmt:	/* CREATE Module */
+				CreateModuleCommand(pstate, (CreateModuleStmt *) parsetree,
+									queryString,
+									pstmt->stmt_location,
+									pstmt->stmt_len);
+				/*
+				 * EventTriggerCollectSimpleCommand called by
+				 * CreateModuleCommand
+				 */
+				commandCollected = true;
+				break;
+
+
 			case T_CreateStmt:
 			case T_CreateForeignTableStmt:
 				{
@@ -2280,6 +2295,9 @@ AlterObjectTypeCommandTag(ObjectType objtype)
 		case OBJECT_STATISTIC_EXT:
 			tag = CMDTAG_ALTER_STATISTICS;
 			break;
+		case OBJECT_MODULE:
+			tag = CMDTAG_ALTER_MODULE;
+			break;
 		default:
 			tag = CMDTAG_UNKNOWN;
 			break;
@@ -2584,6 +2602,9 @@ CreateCommandTag(Node *parsetree)
 				case OBJECT_STATISTIC_EXT:
 					tag = CMDTAG_DROP_STATISTICS;
 					break;
+				case OBJECT_MODULE:
+					tag = CMDTAG_DROP_MODULE;
+					break;
 				default:
 					tag = CMDTAG_UNKNOWN;
 			}
@@ -2739,6 +2760,10 @@ CreateCommandTag(Node *parsetree)
 				tag = CMDTAG_CREATE_FUNCTION;
 			break;
 
+		case T_CreateModuleStmt:
+			tag = CMDTAG_CREATE_MODULE;
+			break;
+
 		case T_IndexStmt:
 			tag = CMDTAG_CREATE_INDEX;
 			break;
@@ -3382,6 +3407,10 @@ GetCommandLogLevel(Node *parsetree)
 			lev = LOGSTMT_DDL;
 			break;
 
+		case T_CreateModuleStmt:
+			lev = LOGSTMT_DDL;
+			break;
+
 		case T_IndexStmt:
 			lev = LOGSTMT_DDL;
 			break;
only in patch2:
unchanged:
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -432,6 +432,7 @@ typedef enum NodeTag
 	T_AlterCollationStmt,
 	T_CallStmt,
 	T_AlterStatsStmt,
+	T_CreateModuleStmt,
 
 	/*
 	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
only in patch2:
unchanged:
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1798,6 +1798,7 @@ typedef enum ObjectType
 	OBJECT_LANGUAGE,
 	OBJECT_LARGEOBJECT,
 	OBJECT_MATVIEW,
+	OBJECT_MODULE,
 	OBJECT_OPCLASS,
 	OBJECT_OPERATOR,
 	OBJECT_OPFAMILY,
@@ -2975,6 +2976,24 @@ typedef struct AlterFunctionStmt
 	List	   *actions;		/* list of DefElem */
 } AlterFunctionStmt;
 
+/* ----------------------
+ *		Create Module Statement
+ *
+ * NOTE: the moduleElts list contains raw parsetrees for component statements
+ * of the schema, such as CREATE FUNCTION, CREATE PROCEDURE, etc.  These are
+ * analyzed and executed after the module itself is created.
+ * ----------------------
+ */
+typedef struct CreateModuleStmt
+{
+	NodeTag		type;
+	List	   *modulename;		/* the name of the schema to create */
+	RoleSpec   *authrole;		/* the owner of the created schema */
+	List	   *moduleElts;		/* module components (list of parsenodes) */
+	bool		if_not_exists;	/* just do nothing if module already exists? */
+} CreateModuleStmt;
+
+
 /* ----------------------
  *		DO Statement
  *
only in patch2:
unchanged:
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -257,6 +257,7 @@ PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, AS_LABEL)
 PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("module", MODULE, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, AS_LABEL)
 PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, BARE_LABEL)
only in patch2:
unchanged:
--- a/src/include/parser/parse_utilcmd.h
+++ b/src/include/parser/parse_utilcmd.h
@@ -31,6 +31,7 @@ extern CreateStatsStmt *transformStatsStmt(Oid relid, CreateStatsStmt *stmt,
 extern void transformRuleStmt(RuleStmt *stmt, const char *queryString,
 							  List **actions, Node **whereClause);
 extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
+extern List *transformCreateModuleStmt(CreateModuleStmt *stmt);
 extern PartitionBoundSpec *transformPartitionBound(ParseState *pstate, Relation parent,
 												   PartitionBoundSpec *spec);
 extern List *expandTableLikeClause(RangeVar *heapRel,
only in patch2:
unchanged:
--- a/src/include/tcop/cmdtaglist.h
+++ b/src/include/tcop/cmdtaglist.h
@@ -43,6 +43,7 @@ PG_CMDTAG(CMDTAG_ALTER_INDEX, "ALTER INDEX", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_LANGUAGE, "ALTER LANGUAGE", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_LARGE_OBJECT, "ALTER LARGE OBJECT", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_MATERIALIZED_VIEW, "ALTER MATERIALIZED VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_MODULE, "ALTER MODULE", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_OPERATOR, "ALTER OPERATOR", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_OPERATOR_CLASS, "ALTER OPERATOR CLASS", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_OPERATOR_FAMILY, "ALTER OPERATOR FAMILY", true, false, false)
@@ -98,6 +99,7 @@ PG_CMDTAG(CMDTAG_CREATE_FUNCTION, "CREATE FUNCTION", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_INDEX, "CREATE INDEX", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_LANGUAGE, "CREATE LANGUAGE", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_MATERIALIZED_VIEW, "CREATE MATERIALIZED VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_MODULE, "CREATE MODULE", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_OPERATOR, "CREATE OPERATOR", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_OPERATOR_CLASS, "CREATE OPERATOR CLASS", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_OPERATOR_FAMILY, "CREATE OPERATOR FAMILY", true, false, false)
@@ -150,6 +152,7 @@ PG_CMDTAG(CMDTAG_DROP_FUNCTION, "DROP FUNCTION", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_INDEX, "DROP INDEX", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_LANGUAGE, "DROP LANGUAGE", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_MATERIALIZED_VIEW, "DROP MATERIALIZED VIEW", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_MODULE, "DROP MODULE", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_OPERATOR, "DROP OPERATOR", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_OPERATOR_CLASS, "DROP OPERATOR CLASS", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_OPERATOR_FAMILY, "DROP OPERATOR FAMILY", true, false, false)
