diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 400ae80..aa4b35e 100644
*** a/src/backend/catalog/Makefile
--- b/src/backend/catalog/Makefile
*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr
*** 37,42 ****
--- 37,43 ----
  	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
  	pg_ts_parser.h pg_ts_template.h \
  	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
+ 	pg_namespace_default_acl.h \
  	toasting.h indexing.h \
      )
  
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index ec4aaf0..d6bfbc5 100644
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
***************
*** 31,36 ****
--- 31,37 ----
  #include "catalog/pg_foreign_server.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_namespace.h"
+ #include "catalog/pg_namespace_default_acl.h"
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
  #include "catalog/pg_opfamily.h"
***************
*** 50,57 ****
  #include "utils/syscache.h"
  #include "utils/tqual.h"
  
! 
  static void ExecGrant_Relation(InternalGrant *grantStmt);
  static void ExecGrant_Database(InternalGrant *grantStmt);
  static void ExecGrant_Fdw(InternalGrant *grantStmt);
  static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
--- 51,60 ----
  #include "utils/syscache.h"
  #include "utils/tqual.h"
  
! static void ExecGrantStmt_Defaults(InternalGrant *istmt);
  static void ExecGrant_Relation(InternalGrant *grantStmt);
+ static void ExecGrantDefaults_Relation(InternalGrant *grantStmt);
+ static void ExecGrantDefaults_Function(InternalGrant *grantStmt);
  static void ExecGrant_Database(InternalGrant *grantStmt);
  static void ExecGrant_Fdw(InternalGrant *grantStmt);
  static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
*************** static void expand_all_col_privileges(Oi
*** 69,76 ****
  						  AclMode this_privileges,
  						  AclMode *col_privileges,
  						  int num_col_privileges);
- static AclMode string_to_privilege(const char *privname);
- static const char *privilege_to_string(AclMode privilege);
  static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
  						 bool all_privs, AclMode privileges,
  						 Oid objectId, Oid grantorId,
--- 72,77 ----
*************** dumpacl(Acl *acl)
*** 105,111 ****
   *
   * NB: the original old_acl is pfree'd.
   */
! static Acl *
  merge_acl_with_grant(Acl *old_acl, bool is_grant,
  					 bool grant_option, DropBehavior behavior,
  					 List *grantees, AclMode privileges,
--- 106,112 ----
   *
   * NB: the original old_acl is pfree'd.
   */
! Acl *
  merge_acl_with_grant(Acl *old_acl, bool is_grant,
  					 bool grant_option, DropBehavior behavior,
  					 List *grantees, AclMode privileges,
*************** restrict_and_check_grant(bool is_grant, 
*** 270,275 ****
--- 271,277 ----
  	return this_privileges;
  }
  
+ 
  /*
   * Called to execute the utility commands GRANT and REVOKE
   */
*************** ExecuteGrantStmt(GrantStmt *stmt)
*** 294,299 ****
--- 296,314 ----
  	istmt.grant_option = stmt->grant_option;
  	istmt.behavior = stmt->behavior;
  
+ 	/* 
+ 	 * GRANT DEFAULT PRIVILEGES 
+ 	 */
+ 	if (!stmt->grantees)
+ 	{
+ 		ExecGrantStmt_Defaults(&istmt);
+ 		return;
+ 	}
+ 
+ 	/* 
+ 	 * Continue with standard GRANT
+ 	 */
+ 
  	/*
  	 * Convert the PrivGrantee list into an Oid list.  Note that at this point
  	 * we insert an ACL_ID_PUBLIC into the list if an empty role name is
*************** ExecGrant_Tablespace(InternalGrant *istm
*** 1988,1994 ****
  }
  
  
! static AclMode
  string_to_privilege(const char *privname)
  {
  	if (strcmp(privname, "insert") == 0)
--- 2003,2222 ----
  }
  
  
! /*
!  * ExecGrantStmt_Defaults
!  *
!  * "Internal" entrypoint for reseting privileges to schema DEFAULT
!  */
! static void
! ExecGrantStmt_Defaults(InternalGrant *istmt)
! {
! 	switch (istmt->objtype)
! 	{
! 		case ACL_OBJECT_RELATION:
! 		case ACL_OBJECT_SEQUENCE:
! 			ExecGrantDefaults_Relation(istmt);
! 			break;
! 		case ACL_OBJECT_FUNCTION:
! 			ExecGrantDefaults_Function(istmt);
! 			break;
! 		default:
! 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! 				 (int) istmt->objtype);
! 	}
! }
! 
! static void
! ExecGrantDefaults_Relation(InternalGrant *grantStmt)
! {
! 	Relation	relation;
! 	ListCell   *cell;
! 
! 	relation = heap_open(RelationRelationId, RowExclusiveLock);
! 
! 	foreach(cell, grantStmt->objects)
! 	{
! 		Oid			relOid = lfirst_oid(cell);
! 		Datum		aclDatum;
! 		Form_pg_class pg_class_tuple;
! 		bool		isNull;
! 		Acl		   *old_acl = NULL;
! 		Acl		   *new_acl;
! 		HeapTuple	tuple;
! 		HeapTuple	newtuple;
! 		Datum		values[Natts_pg_class];
! 		bool		nulls[Natts_pg_class];
! 		bool		replaces[Natts_pg_class];
! 		int			noldmembers;
! 		int			nnewmembers;
! 		Oid		   *oldmembers;
! 		Oid		   *newmembers;
! 		char		objtype;
! 
! 		tuple = SearchSysCache(RELOID,
! 					   ObjectIdGetDatum(relOid),
! 					   0, 0, 0);
! 
! 		if (!HeapTupleIsValid(tuple))
! 			elog(ERROR, "cache lookup failed for relation %u", relOid);
! 		pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
! 
! 		/* Only owner can replace acls */
! 		pg_class_ownercheck(relOid, GetUserId());
! 
! 		aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
! 								   &isNull);
! 		if (!isNull)
! 			old_acl = DatumGetAclPCopy(aclDatum);
! 	
! 		noldmembers = aclmembers(old_acl, &oldmembers);
! 
! 		/* Check relkind and convert it to DefaultACLs object */
! 		switch (pg_class_tuple->relkind)
! 		{
! 			case RELKIND_SEQUENCE:
! 				objtype = NSPDEFACLOBJ_SEQUENCE;
! 				break;
! 			case RELKIND_VIEW:
! 				objtype = NSPDEFACLOBJ_VIEW;
! 				break;
! 			case RELKIND_RELATION:
! 				objtype = NSPDEFACLOBJ_TABLE;
! 				break;
! 			default: /* parser error ? */
! 				elog(ERROR, "relation can't have DEFAULT PRIVILEGES");
! 		}
! 
! 		new_acl = pg_namespace_object_default_acl(pg_class_tuple->relnamespace, 
! 												  objtype, &isNull);
! 
! 		if (isNull)
! 			elog(ERROR, "no DEFAULT PRIVILEGES for relation");
! 
! 		nnewmembers = aclmembers(new_acl, &newmembers);
! 
! 		/* Replace ACLs */
! 		MemSet(values, 0, sizeof(values));
! 		MemSet(nulls, false, sizeof(nulls));
! 		MemSet(replaces, false, sizeof(replaces));
! 
! 		replaces[Anum_pg_class_relacl - 1] = true;
! 		values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
! 
! 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
! 									 values, nulls, replaces);
! 
! 		simple_heap_update(relation, &newtuple->t_self, newtuple);
! 
! 		/* keep the catalog indexes up to date */
! 		CatalogUpdateIndexes(relation, newtuple);
! 
! 		/* Update the shared dependency ACL info */
! 		updateAclDependencies(RelationRelationId, relOid, 0,
! 							  pg_class_tuple->relowner, grantStmt->is_grant,
! 							  noldmembers, oldmembers,
! 							  nnewmembers, newmembers);
! 
! 		pfree(new_acl);
! 
! 		ReleaseSysCache(tuple);
! 
! 		/* prevent error when processing duplicate objects */
! 		CommandCounterIncrement();
! 	}
! 
! 	heap_close(relation, RowExclusiveLock);
! }
! 
! 
! static void
! ExecGrantDefaults_Function(InternalGrant *grantStmt)
! {
! 	Relation	relation;
! 	ListCell   *cell;
! 
! 	relation = heap_open(ProcedureRelationId, RowExclusiveLock);
! 
! 	foreach(cell, grantStmt->objects)
! 	{
! 		Oid			funcId = lfirst_oid(cell);
! 		Form_pg_proc pg_proc_tuple;
! 		Datum		aclDatum;
! 		bool		isNull;
! 		Acl		   *old_acl = NULL;
! 		Acl		   *new_acl;
! 		HeapTuple	tuple;
! 		HeapTuple	newtuple;
! 		Datum		values[Natts_pg_class];
! 		bool		nulls[Natts_pg_class];
! 		bool		replaces[Natts_pg_class];
! 		int			noldmembers;
! 		int			nnewmembers;
! 		Oid		   *oldmembers;
! 		Oid		   *newmembers;
! 
! 		tuple = SearchSysCache(PROCOID,
! 							   ObjectIdGetDatum(funcId),
! 							   0, 0, 0);
! 		if (!HeapTupleIsValid(tuple))
! 			elog(ERROR, "cache lookup failed for function %u", funcId);
! 
! 		pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
! 
! 		/* Only owner can replace acls */
! 		pg_proc_ownercheck(funcId, GetUserId());
! 
! 		aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
! 								   &isNull);
! 
! 		if (!isNull)
! 			old_acl = DatumGetAclPCopy(aclDatum);
! 	
! 		noldmembers = aclmembers(old_acl, &oldmembers);
! 
! 		new_acl = pg_namespace_object_default_acl(pg_proc_tuple->pronamespace, 
! 												  NSPDEFACLOBJ_FUNCTION, &isNull);
! 
! 		if (isNull)
! 			elog(ERROR, "no DEFAULT PRIVILEGES for function");
! 
! 		nnewmembers = aclmembers(new_acl, &newmembers);
! 
! 		/* Replace ACLs */
! 		MemSet(values, 0, sizeof(values));
! 		MemSet(nulls, false, sizeof(nulls));
! 		MemSet(replaces, false, sizeof(replaces));
! 
! 		replaces[Anum_pg_proc_proacl - 1] = true;
! 		values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
! 
! 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
! 									 nulls, replaces);
! 
! 		simple_heap_update(relation, &newtuple->t_self, newtuple);
! 
! 		/* keep the catalog indexes up to date */
! 		CatalogUpdateIndexes(relation, newtuple);
! 
! 		/* Update the shared dependency ACL info */
! 		updateAclDependencies(ProcedureRelationId, funcId, 0,
! 							  pg_proc_tuple->proowner, grantStmt->is_grant,
! 							  noldmembers, oldmembers,
! 							  nnewmembers, newmembers);
! 
! 		ReleaseSysCache(tuple);
! 
! 		pfree(new_acl);
! 
! 		/* prevent error when processing duplicate objects */
! 		CommandCounterIncrement();
! 	}
! 
! 	heap_close(relation, RowExclusiveLock);
! }
! 
! 
! AclMode
  string_to_privilege(const char *privname)
  {
  	if (strcmp(privname, "insert") == 0)
*************** string_to_privilege(const char *privname
*** 2025,2031 ****
  	return 0;					/* appease compiler */
  }
  
! static const char *
  privilege_to_string(AclMode privilege)
  {
  	switch (privilege)
--- 2253,2259 ----
  	return 0;					/* appease compiler */
  }
  
! const char *
  privilege_to_string(AclMode privilege)
  {
  	switch (privilege)
*************** pg_conversion_ownercheck(Oid conv_oid, O
*** 3532,3534 ****
--- 3760,3834 ----
  
  	return has_privs_of_role(roleid, ownerId);
  }
+ 
+ /*
+  * Get default permissions for newly created object inside given schema
+  */
+ Acl *
+ pg_namespace_object_default_acl(Oid nsp_oid, char objtype, bool *isNull)
+ {
+ 	ScanKeyData		key[2];
+ 	HeapScanDesc	scan;
+ 	HeapTuple		tuple;
+ 	Relation		rel;
+ 	Datum			aclDatum;
+ 	Acl			   *result;
+ 
+ 	*isNull = true;
+ 
+ 	/*
+ 	 * Use NULL value for object acls if it is created in system schema
+ 	 * or if it does not have default permissions support (which is usually
+ 	 * because it does not have namespace support either).
+ 	 */
+ 	if (nsp_oid == PG_CATALOG_NAMESPACE || nsp_oid == PG_TOAST_NAMESPACE)
+ 		return NULL;
+ 
+ 	switch (objtype)
+ 	{
+ 		case NSPDEFACLOBJ_TABLE:
+ 		case NSPDEFACLOBJ_VIEW:
+ 		case NSPDEFACLOBJ_FUNCTION:
+ 		case NSPDEFACLOBJ_SEQUENCE:
+ 			break;
+ 
+ 		default:
+ 			return NULL;
+ 	}
+ 
+ 	/*
+ 	 * Search for default permissions for given namespace and objecttype
+ 	 */
+ 	ScanKeyInit(&key[0],
+ 			Anum_pg_namespace_default_acl_defaclnamespace,
+ 			BTEqualStrategyNumber, F_OIDEQ,
+ 			ObjectIdGetDatum(nsp_oid));
+  
+  	ScanKeyInit(&key[1],
+ 			Anum_pg_namespace_default_acl_defaclgrantobjtype,
+ 			BTEqualStrategyNumber, F_CHAREQ,
+ 			CharGetDatum(objtype));
+ 	
+ 	rel = heap_open(NamespaceDefaultAclRelationId, AccessShareLock);
+ 
+ 	scan = heap_beginscan(rel, SnapshotNow, 2, key);
+ 
+ 	tuple = heap_getnext(scan, ForwardScanDirection);
+ 
+ 	if (HeapTupleIsValid(tuple))
+ 	{
+ 		aclDatum = heap_getattr(tuple, Anum_pg_namespace_default_acl_defacldefacllist,
+ 						RelationGetDescr(rel), isNull);
+ 
+ 		result = DatumGetAclPCopy(aclDatum);
+ 	}
+ 	else
+ 	{
+ 		result = NULL;
+ 	}
+ 
+ 	heap_endscan(scan);
+ 	heap_close(rel, AccessShareLock);
+ 
+ 	return result;
+ }
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index f338382..b6467e6 100644
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 37,42 ****
--- 37,43 ----
  #include "catalog/pg_foreign_server.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_namespace.h"
+ #include "catalog/pg_namespace_default_acl.h"
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
  #include "catalog/pg_opfamily.h"
*************** static bool object_address_present_add_f
*** 175,180 ****
--- 176,182 ----
  								 ObjectAddresses *addrs);
  static void getRelationDescription(StringInfo buffer, Oid relid);
  static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
+ static void getDefaultACLDescription(StringInfo buffer, char objtype);
  
  
  /*
*************** doDeletion(const ObjectAddress *object)
*** 1127,1132 ****
--- 1129,1138 ----
  			RemoveForeignDataWrapperById(object->objectId);
  			break;
  
+ 		case OCLASS_NSPDEFACLS:
+ 			RemoveDefaultACLsById(object->objectId);
+ 			break;
+ 
  			/* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
  
  		default:
*************** getObjectClass(const ObjectAddress *obje
*** 2048,2053 ****
--- 2054,2063 ----
  		case UserMappingRelationId:
  			Assert(object->objectSubId == 0);
  			return OCLASS_USER_MAPPING;
+ 
+ 		case NamespaceDefaultAclRelationId:
+ 			Assert(object->objectSubId == 0);
+ 			return OCLASS_NSPDEFACLS;
  	}
  
  	/* shouldn't get here */
*************** getObjectDescription(const ObjectAddress
*** 2590,2595 ****
--- 2600,2643 ----
  				break;
  			}
  
+ 		case OCLASS_NSPDEFACLS:
+ 			{
+ 				Relation	rel;
+ 				ScanKeyData key[1];
+ 				HeapScanDesc scan;
+ 				HeapTuple	tup;
+ 				char	   *nspname;
+ 				Form_pg_namespace_default_acl nspda;
+ 
+ 				rel = heap_open(NamespaceDefaultAclRelationId, AccessShareLock);
+ 
+ 				ScanKeyInit(&key[0],
+ 							ObjectIdAttributeNumber,
+ 							BTEqualStrategyNumber, F_OIDEQ,
+ 							ObjectIdGetDatum(object->objectId));
+ 
+ 				scan = heap_beginscan(rel, SnapshotNow, 1, key);
+ 
+ 				tup = heap_getnext(scan, ForwardScanDirection);
+ 
+ 				if (!HeapTupleIsValid(tup))
+ 					elog(ERROR, "could not find tuple for default acls %u",
+ 						 object->objectId);
+ 
+ 				nspda = (Form_pg_namespace_default_acl) GETSTRUCT(tup);
+ 
+ 				nspname = get_namespace_name(nspda->defaclnamespace);
+ 
+ 				appendStringInfo(&buffer, 
+ 								_("default acls in namespace %s for new "),
+ 								nspname);
+ 				getDefaultACLDescription(&buffer, nspda->defaclobjtype);
+ 
+ 				heap_endscan(scan);
+ 				heap_close(rel, AccessShareLock);
+ 				break;
+ 			}
+ 
  		default:
  			appendStringInfo(&buffer, "unrecognized object %u %u %d",
  							 object->classId,
*************** getOpFamilyDescription(StringInfo buffer
*** 2708,2710 ****
--- 2756,2784 ----
  	ReleaseSysCache(amTup);
  	ReleaseSysCache(opfTup);
  }
+ 
+ 
+ /*
+  * subroutine for getObjectDescription: describe DefaultACLs object type
+  */
+ static void
+ getDefaultACLDescription(StringInfo buffer, char objtype)
+ {
+ 	switch (objtype)
+ 	{
+ 		case NSPDEFACLOBJ_TABLE:
+ 			appendStringInfo(buffer, _("TABLE"));
+ 			break;
+ 		case NSPDEFACLOBJ_VIEW:
+ 			appendStringInfo(buffer, _("VIEW"));
+ 			break;
+ 		case NSPDEFACLOBJ_FUNCTION:
+ 			appendStringInfo(buffer, _("FUNCTION"));
+ 			break;
+ 		case NSPDEFACLOBJ_SEQUENCE:
+ 			appendStringInfo(buffer, _("SEQUENCE"));
+ 			break;
+ 		default:
+ 			appendStringInfo(buffer, _("unknown"));
+ 	}
+ }
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 7557400..054c80c 100644
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 67,72 ****
--- 67,73 ----
  #include "utils/snapmgr.h"
  #include "utils/syscache.h"
  #include "utils/tqual.h"
+ #include "utils/acl.h"
  
  
  static void AddNewRelationTuple(Relation pg_class_desc,
*************** InsertPgClassTuple(Relation pg_class_des
*** 646,651 ****
--- 647,654 ----
  	Form_pg_class rd_rel = new_rel_desc->rd_rel;
  	Datum		values[Natts_pg_class];
  	bool		nulls[Natts_pg_class];
+ 	bool		isNull;
+ 	Acl		   *relacl;
  	HeapTuple	tup;
  
  	/* This is a tad tedious, but way cleaner than what we used to do... */
*************** InsertPgClassTuple(Relation pg_class_des
*** 675,682 ****
  	values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
  	values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
  	values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
! 	/* start out with empty permissions */
! 	nulls[Anum_pg_class_relacl - 1] = true;
  	if (reloptions != (Datum) 0)
  		values[Anum_pg_class_reloptions - 1] = reloptions;
  	else
--- 678,691 ----
  	values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
  	values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
  	values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
! 	
! 	/* get default permissions */
! 	relacl = pg_namespace_object_default_acl(rd_rel->relnamespace, rd_rel->relkind, &isNull);
! 	if (isNull)
! 		nulls[Anum_pg_class_relacl - 1] = true;
! 	else
! 		values[Anum_pg_class_relacl - 1] = PointerGetDatum(relacl);
! 
  	if (reloptions != (Datum) 0)
  		values[Anum_pg_class_reloptions - 1] = reloptions;
  	else
*************** InsertPgClassTuple(Relation pg_class_des
*** 695,700 ****
--- 704,724 ----
  
  	CatalogUpdateIndexes(pg_class_desc, tup);
  
+ 	if (!isNull)
+ 	{
+ 		int			nnewmembers;
+ 		Oid		   *newmembers;
+ 
+ 		/* Update the shared dependency ACL info */
+ 		nnewmembers = aclmembers(relacl, &newmembers);
+ 		updateAclDependencies(RelationRelationId, new_rel_oid, 0,
+ 						  rd_rel->relowner, true,
+ 						  0, NULL,
+ 						  nnewmembers, newmembers);
+ 
+ 		pfree(relacl);
+ 	}
+ 
  	heap_freetuple(tup);
  }
  
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 1a06530..8ffb552 100644
*** a/src/backend/catalog/pg_proc.c
--- b/src/backend/catalog/pg_proc.c
***************
*** 20,25 ****
--- 20,26 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_namespace.h"
+ #include "catalog/pg_namespace_default_acl.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_proc_fn.h"
  #include "catalog/pg_type.h"
*************** ProcedureCreate(const char *procedureNam
*** 95,100 ****
--- 96,103 ----
  	bool		nulls[Natts_pg_proc];
  	Datum		values[Natts_pg_proc];
  	bool		replaces[Natts_pg_proc];
+ 	bool		isNull;
+ 	Acl		   *proacl;
  	Oid			relid;
  	NameData	procname;
  	TupleDesc	tupDesc;
*************** ProcedureCreate(const char *procedureNam
*** 330,337 ****
  		values[Anum_pg_proc_proconfig - 1] = proconfig;
  	else
  		nulls[Anum_pg_proc_proconfig - 1] = true;
! 	/* start out with empty permissions */
! 	nulls[Anum_pg_proc_proacl - 1] = true;
  
  	rel = heap_open(ProcedureRelationId, RowExclusiveLock);
  	tupDesc = RelationGetDescr(rel);
--- 333,345 ----
  		values[Anum_pg_proc_proconfig - 1] = proconfig;
  	else
  		nulls[Anum_pg_proc_proconfig - 1] = true;
! 
! 	/* get default permissions */
! 	proacl = pg_namespace_object_default_acl(procNamespace, NSPDEFACLOBJ_FUNCTION, &isNull);
! 	if (isNull)
! 		nulls[Anum_pg_proc_proacl - 1] = true;
! 	else
! 		values[Anum_pg_proc_proacl - 1] = PointerGetDatum(proacl);
  
  	rel = heap_open(ProcedureRelationId, RowExclusiveLock);
  	tupDesc = RelationGetDescr(rel);
*************** ProcedureCreate(const char *procedureNam
*** 539,544 ****
--- 547,567 ----
  	/* dependency on owner */
  	recordDependencyOnOwner(ProcedureRelationId, retval, GetUserId());
  
+ 	if (!isNull)
+ 	{
+ 		int			nnewmembers;
+ 		Oid		   *newmembers;
+ 
+ 		/* Update the shared dependency ACL info */
+ 		nnewmembers = aclmembers(proacl, &newmembers);
+ 		updateAclDependencies(ProcedureRelationId, retval, 0,
+ 						  GetUserId(), true,
+ 						  0, NULL,
+ 						  nnewmembers, newmembers);
+ 
+ 		pfree(proacl);
+ 	}
+ 
  	heap_freetuple(tup);
  
  	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index c70d4a8..c33bedd 100644
*** a/src/backend/commands/schemacmds.c
--- b/src/backend/commands/schemacmds.c
***************
*** 16,26 ****
--- 16,28 ----
  
  #include "access/heapam.h"
  #include "access/xact.h"
+ #include "access/sysattr.h"
  #include "catalog/catalog.h"
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_namespace.h"
+ #include "catalog/pg_namespace_default_acl.h"
  #include "commands/dbcommands.h"
  #include "commands/schemacmds.h"
  #include "miscadmin.h"
***************
*** 28,38 ****
--- 30,57 ----
  #include "tcop/utility.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
+ #include "utils/fmgroids.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
+ #include "utils/tqual.h"
+ 
+ 
+ 
+ typedef struct
+ {
+ 	int			action;
+ 	Oid			nspId;
+ 	Oid			nspOwnerId;
+ 	GrantObjectType objtype;
+ 	AclMode		privileges;
+ 	List	   *grantees;
+ 	bool		grant_option;
+ } InternalDefaultACLs;
+ 
  
  
  static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId);
+ static void SetDefaultACLs(InternalDefaultACLs *iacls);
  
  /*
   * CREATE SCHEMA
*************** CreateSchemaCommand(CreateSchemaStmt *st
*** 147,152 ****
--- 166,520 ----
  }
  
  
+ 
+ /*
+  * Default ACLs
+  *		Implements ALTER SCHEMA DEFAULT PRIVILEGES
+  */
+ void
+ DefaultACLsCommand(DefaultACLsStmt *stmt)
+ {
+ 	InternalDefaultACLs iacls;
+ 	List	   *objlist;
+ 	ListCell   *objcell;
+ 	ListCell   *privcell;
+ 	ListCell   *cell;
+ 	Relation	relation;
+ 	HeapTuple	tuple;
+ 	const char *errormsg;
+ 	AclMode		all_privileges;
+ 	Form_pg_namespace pg_namespace_tuple;
+ 
+ 	relation = heap_open(NamespaceRelationId, RowExclusiveLock);
+ 
+ 	tuple = SearchSysCache(NAMESPACENAME,
+                            CStringGetDatum(stmt->schemaname),
+ 						   0, 0, 0);
+ 
+ 	if (!HeapTupleIsValid(tuple))
+ 		elog(ERROR, "cache lookup failed for namespace \"%s\"", stmt->schemaname);
+ 
+ 	iacls.nspId = HeapTupleGetOid(tuple);
+ 	pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
+ 	iacls.nspOwnerId = pg_namespace_tuple->nspowner;
+ 
+ 	if (iacls.nspId == PG_CATALOG_NAMESPACE || iacls.nspId == PG_TOAST_NAMESPACE)
+ 		elog(ERROR, "can't set default permissions for system catalog");
+ 
+ 	/* Permission check */
+ 	if (!pg_namespace_ownercheck(iacls.nspId, GetUserId()))
+ 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+ 					   stmt->schemaname);
+ 
+ 	objlist = transformDefaultACLsStmt(stmt);
+ 
+ 	foreach(objcell, stmt->objlist)
+ 	{
+ 		DefaultACLsObject *object = (DefaultACLsObject *) lfirst(objcell);
+ 
+ 		iacls.action = stmt->action;
+ 		iacls.objtype = object->objtype;
+ 
+ 		/*
+ 		 * Set allowed privileges and apropriate error message for object type
+ 		 * used in privilege conversion few lines down
+ 		 */
+ 		switch (object->objtype)
+ 		{
+ 			case NSP_ACL_OBJ_RELATION:
+ 				all_privileges = ACL_ALL_RIGHTS_RELATION;
+ 				errormsg = gettext_noop("invalid privilege type %s for relation");
+ 				break;
+ 			case NSP_ACL_OBJ_VIEW:
+ 				all_privileges = ACL_ALL_RIGHTS_RELATION;
+ 				errormsg = gettext_noop("invalid privilege type %s for view");
+ 				break;
+ 			case NSP_ACL_OBJ_FUNCTION:
+ 				all_privileges = ACL_ALL_RIGHTS_FUNCTION;
+ 				errormsg = gettext_noop("invalid privilege type %s for function");
+ 				break;
+ 			case NSP_ACL_OBJ_SEQUENCE:
+ 				all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
+ 				errormsg = gettext_noop("invalid privilege type %s for sequence");
+ 				break;
+ 			default:
+ 				/* keep compiler quiet */
+ 				all_privileges = ACL_NO_RIGHTS;
+ 				errormsg = NULL;
+ 				elog(ERROR, "unrecognized DefaultACLsObject.objtype: %d",
+ 					 (int) object->objtype);
+ 		}
+ 
+ 		foreach(privcell, object->privileges)
+ 		{
+ 			DefaultACLsPriv *privs = (DefaultACLsPriv *) lfirst(privcell);
+ 
+ 			iacls.grantees = NIL;
+ 			iacls.grant_option = privs->grant_option;
+ 
+ 			foreach(cell, privs->grantees)
+ 			{
+ 				PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ 
+ 				if (grantee->rolname == NULL)
+ 					iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
+ 				else
+ 					iacls.grantees =
+ 						lappend_oid(iacls.grantees,
+ 							get_roleid_checked(grantee->rolname));
+ 			}
+ 
+ 			/*
+ 			 * Convert DefaultACLsPriv->privileges, a list of privilege strings,
+ 			 * into an AclMode bitmask.
+ 			 */
+ 			if (privs->privileges == NIL)
+ 			{
+ 				iacls.privileges = all_privileges;
+ 			}
+ 			else
+ 			{
+ 				iacls.privileges = ACL_NO_RIGHTS;
+ 
+ 				foreach(cell, privs->privileges)
+ 				{
+ 					char	   *priv_name = (char *) lfirst(cell);
+ 					AclMode		priv;
+ 
+ 					priv = string_to_privilege(priv_name);
+ 
+ 					if (priv & ~((AclMode) all_privileges))
+ 						ereport(ERROR,
+ 								(errcode(ERRCODE_INVALID_GRANT_OPERATION),
+ 								 errmsg(errormsg, privilege_to_string(priv))));
+ 
+ 					iacls.privileges |= priv;
+ 				}
+ 			}
+ 
+ 			/* Apply the privileges */
+ 			SetDefaultACLs(&iacls);
+ 
+ 			/* If this is SET command chnage it to ADD for subsequent privileges */
+ 			if (iacls.action == 0)
+ 				iacls.action = 1;
+ 		}
+ 	}
+ 
+ 	ReleaseSysCache(tuple);
+ 
+ 	heap_close(relation, RowExclusiveLock);
+ }
+ 
+ 
+ /*
+  * Create or update the DefaultACL entry
+  */
+ void
+ SetDefaultACLs(InternalDefaultACLs *iacls)
+ {
+ 	Form_pg_namespace_default_acl pg_namespace_default_acl_tuple;
+ 	char		objtype;
+ 	Datum		aclDatum;
+ 	bool		isNull;
+ 	bool		isNew;
+ 	ScanKeyData key[2];
+ 	HeapScanDesc scan;
+ 	HeapTuple	tuple;
+ 	Relation	rel;
+ 	Acl		   *old_acl;
+ 	Acl		   *base_acl;
+ 	Acl		   *new_acl;
+ 	HeapTuple	newtuple;	
+ 	Datum		values[Natts_pg_namespace_default_acl];
+ 	bool		nulls[Natts_pg_namespace_default_acl];
+ 	bool		replaces[Natts_pg_namespace_default_acl];
+ 	int			noldmembers;
+ 	int			nnewmembers;
+ 	Oid		   *oldmembers;
+ 	Oid		   *newmembers;
+ 
+ 	/*
+ 	 * Convert ACL object type to DefaultACLs object type
+ 	 */
+ 	switch (iacls->objtype)
+ 	{
+ 		case NSP_ACL_OBJ_RELATION:
+ 			objtype = NSPDEFACLOBJ_TABLE;
+ 			break;
+ 
+ 		case NSP_ACL_OBJ_VIEW:
+ 			objtype = NSPDEFACLOBJ_VIEW;
+ 			break;
+ 
+ 		case NSP_ACL_OBJ_FUNCTION:
+ 			objtype = NSPDEFACLOBJ_FUNCTION;
+ 			break;
+ 
+ 		case NSP_ACL_OBJ_SEQUENCE:
+ 			objtype = NSPDEFACLOBJ_SEQUENCE;
+ 			break;
+ 
+ 		default:
+ 			elog(ERROR, "unrecognized objtype: %d",
+ 				 (int) iacls->objtype);
+ 			objtype = 0;		/* keep compiler quiet */
+ 			break;
+ 	}
+ 
+ 	/* Search for existing row for our object type in catalog */
+ 	ScanKeyInit(&key[0],
+ 			Anum_pg_namespace_default_acl_defaclnamespace,
+ 			BTEqualStrategyNumber, F_OIDEQ,
+ 			ObjectIdGetDatum(iacls->nspId));
+  
+  	ScanKeyInit(&key[1],
+ 			Anum_pg_namespace_default_acl_defaclgrantobjtype,
+ 			BTEqualStrategyNumber, F_CHAREQ,
+ 			CharGetDatum(objtype));
+ 
+ 	rel = heap_open(NamespaceDefaultAclRelationId, RowExclusiveLock);
+ 
+ 	scan = heap_beginscan(rel, SnapshotNow, 2, key);
+ 		
+ 	tuple = heap_getnext(scan, ForwardScanDirection);
+ 	if (HeapTupleIsValid(tuple))
+ 	{
+ 		pg_namespace_default_acl_tuple = (Form_pg_namespace_default_acl) GETSTRUCT(tuple);
+ 		aclDatum = heap_getattr(tuple, Anum_pg_namespace_default_acl_defacldefacllist,
+ 						RelationGetDescr(rel), &isNull);
+ 		isNew = false;
+ 	}
+ 	else
+ 	{
+ 		isNull = true;
+ 		isNew = true;
+ 	}
+ 
+ 	/* 
+ 	 * If there are no default privileges for current schema and object type 
+ 	 * or if we are SETting the privileges, use the default privileges 
+ 	 * based on object type.
+ 	 */
+ 	if (isNull)
+ 		old_acl = acldefault(ACL_OBJECT_RELATION, iacls->nspOwnerId);
+ 	else
+ 		old_acl = DatumGetAclPCopy(aclDatum);
+ 
+ 	if (iacls->action == 0)
+ 		base_acl = acldefault(ACL_OBJECT_RELATION, iacls->nspOwnerId);
+ 	else
+ 		base_acl = old_acl;
+ 	
+ 	/*
+ 	 * Generate new ACL.
+ 	 *
+ 	 * We need the members of both old and new ACLs so we can correct
+ 	 * the shared dependency information.
+ 	 */
+ 	noldmembers = aclmembers(old_acl, &oldmembers);
+ 
+ 	new_acl = merge_acl_with_grant(base_acl,
+ 								   iacls->action != -1,
+ 								   iacls->grant_option,
+ 								   DROP_RESTRICT, // this shouldn't affect us at all
+ 								   iacls->grantees,
+ 								   iacls->privileges,
+ 								   GetUserId(),
+ 								   iacls->nspOwnerId);
+ 
+ 	nnewmembers = aclmembers(new_acl, &newmembers);
+ 
+ 	/* finished building new ACL value, now insert it */
+ 	MemSet(values, 0, sizeof(values));
+ 	MemSet(nulls, false, sizeof(nulls));
+ 	MemSet(replaces, false, sizeof(replaces));
+ 
+ 	if (isNew)
+ 	{
+ 		ObjectAddress myself,
+ 					referenced;
+ 
+ 		values[Anum_pg_namespace_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspId);
+ 		values[Anum_pg_namespace_default_acl_defaclgrantobjtype - 1] = CharGetDatum(objtype);
+ 		values[Anum_pg_namespace_default_acl_defacldefacllist - 1] = PointerGetDatum(new_acl);
+ 
+ 		newtuple = heap_form_tuple(rel->rd_att, values, nulls);
+ 		simple_heap_insert(rel, newtuple);
+ 
+ 		myself.classId = NamespaceDefaultAclRelationId;
+ 		myself.objectId = HeapTupleGetOid(newtuple);
+ 		myself.objectSubId = 0;
+ 
+ 		/* dependency on namespace */
+ 		referenced.classId = NamespaceRelationId;
+ 		referenced.objectId = iacls->nspId;
+ 		referenced.objectSubId = 0;
+ 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ 	}
+ 	else
+ 	{
+ 		replaces[Anum_pg_namespace_default_acl_defacldefacllist - 1] = true;
+ 		values[Anum_pg_namespace_default_acl_defacldefacllist - 1] = PointerGetDatum(new_acl);
+ 
+ 		newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
+ 								 values, nulls, replaces);
+ 		simple_heap_update(rel, &newtuple->t_self, newtuple);
+ 	}
+ 
+ 	/* keep the catalog indexes up to date */
+ 	CatalogUpdateIndexes(rel, newtuple);
+ 
+ 	/* Update the shared dependency ACL info */
+ 	updateAclDependencies(NamespaceDefaultAclRelationId, HeapTupleGetOid(newtuple), 0,
+ 						  iacls->nspOwnerId, iacls->action != -1,
+ 						  noldmembers, oldmembers,
+ 						  nnewmembers, newmembers);
+ 
+ 	pfree(new_acl);
+ 
+ 	/* prevent error when processing duplicate objects */
+ 	CommandCounterIncrement();
+ 
+ 	heap_endscan(scan);
+ 	heap_close(rel, RowExclusiveLock);
+ }
+ 
+ 
+ /*
+  * Remove DefaultACLs tuple.
+  */
+ void
+ RemoveDefaultACLsById(Oid nsdaOid)
+ {
+ 	Relation	rel;
+ 	ScanKeyData key[1];
+ 	HeapScanDesc scan;
+ 	HeapTuple	tup;
+ 
+ 	rel = heap_open(NamespaceDefaultAclRelationId, RowExclusiveLock);
+ 
+ 	ScanKeyInit(&key[0],
+ 				ObjectIdAttributeNumber,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(nsdaOid));
+ 
+ 	scan = heap_beginscan(rel, SnapshotNow, 1, key);
+ 
+ 	tup = heap_getnext(scan, ForwardScanDirection);
+ 
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "could not find tuple for default acls %u",
+ 			 nsdaOid);
+ 
+ 	simple_heap_delete(rel, &tup->t_self);
+ 
+ 	heap_endscan(scan);
+ 	heap_close(rel, RowExclusiveLock);
+ }
+ 
+ 
+ 
  /*
   *	RemoveSchemas
   *		Implements DROP SCHEMA.
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 2c7d481..5fc79e9 100644
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
*************** _copyCreateSchemaStmt(CreateSchemaStmt *
*** 3224,3229 ****
--- 3224,3241 ----
  	return newnode;
  }
  
+ static DefaultACLsStmt *
+ _copyDefaultACLsStmt(DefaultACLsStmt *from)
+ {
+ 	DefaultACLsStmt *newnode = makeNode(DefaultACLsStmt);
+ 
+ 	COPY_STRING_FIELD(schemaname);
+ 	COPY_SCALAR_FIELD(action);
+ 	COPY_NODE_FIELD(objlist);
+ 
+ 	return newnode;
+ }
+ 
  static CreateConversionStmt *
  _copyCreateConversionStmt(CreateConversionStmt *from)
  {
*************** copyObject(void *from)
*** 3966,3971 ****
--- 3978,3986 ----
  		case T_CreateSchemaStmt:
  			retval = _copyCreateSchemaStmt(from);
  			break;
+ 		case T_DefaultACLsStmt:
+ 			retval = _copyDefaultACLsStmt(from);
+ 			break;
  		case T_CreateConversionStmt:
  			retval = _copyCreateConversionStmt(from);
  			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index c61de97..96f2bed 100644
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
*************** _equalCreateSchemaStmt(CreateSchemaStmt 
*** 1761,1766 ****
--- 1761,1776 ----
  }
  
  static bool
+ _equalDefaultACLsStmt(DefaultACLsStmt *a, DefaultACLsStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(schemaname);
+ 	COMPARE_SCALAR_FIELD(action);
+ 	COMPARE_NODE_FIELD(objlist);
+ 
+ 	return true;
+ }
+ 
+ static bool
  _equalCreateConversionStmt(CreateConversionStmt *a, CreateConversionStmt *b)
  {
  	COMPARE_NODE_FIELD(conversion_name);
*************** equal(void *a, void *b)
*** 2743,2748 ****
--- 2753,2761 ----
  		case T_CreateSchemaStmt:
  			retval = _equalCreateSchemaStmt(a, b);
  			break;
+ 		case T_DefaultACLsStmt:
+ 			retval = _equalDefaultACLsStmt(a, b);
+ 			break;
  		case T_CreateConversionStmt:
  			retval = _equalCreateConversionStmt(a, b);
  			break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 3f4eca7..da8f112 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** static TypeName *TableFuncTypeName(List 
*** 179,184 ****
--- 179,187 ----
  	ResTarget			*target;
  	struct PrivTarget	*privtarget;
  	AccessPriv			*accesspriv;
+ 	ACLSchemaObjectType	aclschemaobjecttype;
+ 	DefaultACLsObject	*defaultaclsobject;
+ 	DefaultACLsPriv		*defaultaclspriv;
  
  	InsertStmt			*istmt;
  	VariableSetStmt		*vsetstmt;
*************** static TypeName *TableFuncTypeName(List 
*** 196,202 ****
  		CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
  		CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
  		CreateUserStmt CreateUserMappingStmt CreateRoleStmt
! 		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt
  		DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
  		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
  		DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
--- 199,205 ----
  		CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
  		CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
  		CreateUserStmt CreateUserMappingStmt CreateRoleStmt
! 		CreatedbStmt DeclareCursorStmt DefaultACLsStmt DefaultACLsDropStmt DefineStmt DeleteStmt DiscardStmt
  		DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
  		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
  		DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
*************** static TypeName *TableFuncTypeName(List 
*** 218,224 ****
  				simple_select values_clause
  
  %type <node>	alter_column_default opclass_item opclass_drop alter_using
! %type <ival>	add_drop opt_asc_desc opt_nulls_order
  
  %type <node>	alter_table_cmd
  %type <list>	alter_table_cmds
--- 221,227 ----
  				simple_select values_clause
  
  %type <node>	alter_column_default opclass_item opclass_drop alter_using
! %type <ival>	add_drop set_add opt_asc_desc opt_nulls_order
  
  %type <node>	alter_table_cmd
  %type <list>	alter_table_cmds
*************** static TypeName *TableFuncTypeName(List 
*** 266,273 ****
  %type <node>	grantee
  %type <list>	grantee_list
  %type <accesspriv> privilege
! %type <list>	privileges privilege_list
  %type <privtarget> privilege_target
  %type <funwithargs> function_with_argtypes
  %type <list>	function_with_argtypes_list
  
--- 269,282 ----
  %type <node>	grantee
  %type <list>	grantee_list
  %type <accesspriv> privilege
! %type <list>	default_acls_object_list default_acls_object_list_drop 
! 				default_acls_priv_list default_acls_priv_list_drop default_priv_list 
! 				default_priv_type privileges privilege_list
  %type <privtarget> privilege_target
+ %type <aclschemaobjecttype>	default_priv_target
+ %type <defaultaclsobject>	default_acls_object default_acls_object_drop
+ %type <defaultaclspriv>	default_acls_priv default_acls_priv_drop
+ %type <str>	default_priv
  %type <funwithargs> function_with_argtypes
  %type <list>	function_with_argtypes_list
  
*************** static TypeName *TableFuncTypeName(List 
*** 326,332 ****
  %type <boolean> opt_freeze opt_default opt_recheck
  %type <defelt>	opt_binary opt_oids copy_delimiter
  
! %type <boolean> copy_from
  
  %type <ival>	opt_column event cursor_options opt_hold opt_set_data
  %type <objtype>	reindex_type drop_type comment_type
--- 335,341 ----
  %type <boolean> opt_freeze opt_default opt_recheck
  %type <defelt>	opt_binary opt_oids copy_delimiter
  
! %type <boolean> to_from
  
  %type <ival>	opt_column event cursor_options opt_hold opt_set_data
  %type <objtype>	reindex_type drop_type comment_type
*************** stmt :
*** 653,658 ****
--- 662,669 ----
  			| CreatedbStmt
  			| DeallocateStmt
  			| DeclareCursorStmt
+ 			| DefaultACLsStmt
+ 			| DefaultACLsDropStmt
  			| DefineStmt
  			| DeleteStmt
  			| DiscardStmt
*************** schema_stmt:
*** 1094,1099 ****
--- 1105,1236 ----
  		;
  
  
+ 
+ /*****************************************************************************
+  *
+  * DEFAULT PRIVILEGES for newly created objects in schema
+  *
+  *****************************************************************************/
+ 
+ DefaultACLsStmt:
+ 			ALTER SCHEMA name set_add DEFAULT PRIVILEGES 
+ 			default_acls_object_list 
+ 				{
+ 					DefaultACLsStmt *n = makeNode(DefaultACLsStmt);
+ 					n->schemaname = $3;
+ 					n->action = $4;
+ 					n->objlist = $7;
+ 					$$ = (Node*)n;
+ 				}
+ 		;
+ 
+ DefaultACLsDropStmt:
+ 			ALTER SCHEMA name DROP DEFAULT PRIVILEGES 
+ 			default_acls_object_list_drop
+ 				{
+ 					DefaultACLsStmt *n = makeNode(DefaultACLsStmt);
+ 					n->schemaname = $3;
+ 					n->action = -1;
+ 					n->objlist = $7;
+ 					$$ = (Node*)n;
+ 				}
+ 		;
+ 
+ set_add:	SET									{ $$ =  0; }
+ 			| ADD_P								{ $$ = +1; }
+ 		;
+ 
+ default_acls_object:
+ 			ON default_priv_target default_acls_priv_list
+ 				{
+ 					DefaultACLsObject *n = makeNode(DefaultACLsObject);
+ 					n->objtype = $2;
+ 					n->privileges = $3;
+ 					$$ = n;
+ 				}
+ 		;
+ 
+ default_acls_object_list:	
+ 			default_acls_object								{ $$ = list_make1($1); }
+ 			| default_acls_object_list default_acls_object	{ $$ = lappend($1, $2); }
+ 		;
+ 
+ default_acls_priv:
+ 			default_priv_type TO grantee_list opt_grant_grant_option
+ 				{
+ 					DefaultACLsPriv *n = makeNode(DefaultACLsPriv);
+ 					n->privileges = $1;
+ 					n->grantees = $3;
+ 					n->grant_option = $4;
+ 					$$ = n;
+ 				}
+ 		;
+ 
+ default_acls_priv_list:	
+ 			default_acls_priv								{ $$ = list_make1($1); }
+ 			| default_acls_priv_list AND default_acls_priv	{ $$ = lappend($1, $3); }
+ 		;
+ 
+ default_acls_object_drop:
+ 			ON default_priv_target default_acls_priv_list_drop
+ 				{
+ 					DefaultACLsObject *n = makeNode(DefaultACLsObject);
+ 					n->objtype = $2;
+ 					n->privileges = $3;
+ 					$$ = n;
+ 				}
+ 		;
+ 
+ default_acls_object_list_drop:	
+ 			default_acls_object_drop									{ $$ = list_make1($1); }
+ 			| default_acls_object_list_drop default_acls_object_drop	{ $$ = lappend($1, $2); }
+ 		;
+ 
+ default_acls_priv_drop:
+ 			default_priv_type FROM grantee_list opt_grant_grant_option
+ 				{
+ 					DefaultACLsPriv *n = makeNode(DefaultACLsPriv);
+ 					n->privileges = $1;
+ 					n->grantees = $3;
+ 					n->grant_option = $4;
+ 					$$ = n;
+ 				}
+ 		;
+ 
+ default_acls_priv_list_drop:	
+ 			default_acls_priv_drop										{ $$ = list_make1($1); }
+ 			| default_acls_priv_list_drop AND default_acls_priv_drop	{ $$ = lappend($1, $3); }
+ 		;
+ 
+ default_priv_type:
+ 			default_priv_list
+ 				{ $$ = $1; }
+ 			| ALL
+ 				{ $$ = NIL; }
+ 			| ALL PRIVILEGES
+ 				{ $$ = NIL; }
+ 		;
+ 
+ default_priv_list:
+ 			default_priv							{ $$ = list_make1($1); }
+ 			| default_priv_list ',' default_priv	{ $$ = lappend($1, $3); }
+ 		;
+ 
+ default_priv: 
+ 			SELECT									{ $$ = pstrdup($1); }
+ 			| REFERENCES							{ $$ = pstrdup($1); }
+ 			| CREATE								{ $$ = pstrdup($1); }
+ 			| ColId									{ $$ = $1; }
+ 		;
+ 
+ default_priv_target:
+ 			TABLE									{ $$ = NSP_ACL_OBJ_RELATION; }
+ 			| VIEW									{ $$ = NSP_ACL_OBJ_VIEW; }
+ 			| FUNCTION								{ $$ = NSP_ACL_OBJ_FUNCTION; }
+ 			| SEQUENCE								{ $$ = NSP_ACL_OBJ_SEQUENCE; }
+ 		;
+ 
+ 
  /*****************************************************************************
   *
   * Set PG internal variable
*************** ClosePortalStmt:
*** 1899,1905 ****
   *****************************************************************************/
  
  CopyStmt:	COPY opt_binary qualified_name opt_column_list opt_oids
! 			copy_from copy_file_name copy_delimiter opt_with copy_opt_list
  				{
  					CopyStmt *n = makeNode(CopyStmt);
  					n->relation = $3;
--- 2036,2042 ----
   *****************************************************************************/
  
  CopyStmt:	COPY opt_binary qualified_name opt_column_list opt_oids
! 			to_from copy_file_name copy_delimiter opt_with copy_opt_list
  				{
  					CopyStmt *n = makeNode(CopyStmt);
  					n->relation = $3;
*************** CopyStmt:	COPY opt_binary qualified_name
*** 1934,1940 ****
  				}
  		;
  
! copy_from:
  			FROM									{ $$ = TRUE; }
  			| TO									{ $$ = FALSE; }
  		;
--- 2071,2077 ----
  				}
  		;
  
! to_from:
  			FROM									{ $$ = TRUE; }
  			| TO									{ $$ = FALSE; }
  		;
*************** GrantStmt:	GRANT privileges ON privilege
*** 4227,4232 ****
--- 4364,4380 ----
  					n->grant_option = $7;
  					$$ = (Node*)n;
  				}
+ 			| GRANT DEFAULT PRIVILEGES ON privilege_target
+ 				{
+ 					GrantStmt *n = makeNode(GrantStmt);
+ 					n->is_grant = true;
+ 					n->privileges = NIL;
+ 					n->objtype = ($5)->objtype;
+ 					n->objects = ($5)->objs;
+ 					n->grantees = NIL;
+ 					n->grant_option = FALSE;
+ 					$$ = (Node*)n;
+ 				}
  		;
  
  RevokeStmt:
*************** privilege_target:
*** 4343,4348 ****
--- 4491,4503 ----
  					n->objs = $2;
  					$$ = n;
  				}
+ 			| VIEW qualified_name_list
+ 				{
+ 					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ 					n->objtype = ACL_OBJECT_RELATION;
+ 					n->objs = $2;
+ 					$$ = n;
+ 				}
  			| SEQUENCE qualified_name_list
  				{
  					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 2bcf261..f9d6d85 100644
*** a/src/backend/parser/parse_utilcmd.c
--- b/src/backend/parser/parse_utilcmd.c
*************** typedef struct
*** 91,96 ****
--- 91,104 ----
  	List	   *grants;			/* GRANT items */
  } CreateSchemaStmtContext;
  
+ /* State for transformDefaultACLsStmt */
+ typedef struct
+ {
+ 	DefaultACLsObject   *table;				/* TABLE permissions */
+ 	DefaultACLsObject   *view;				/* VIEW permissions */
+ 	DefaultACLsObject   *function;			/* FUNCTION permissions */
+ 	DefaultACLsObject   *sequence;			/* SEQUENCE permissions */
+ } DefaultACLsStmtContext;
  
  static void transformColumnDefinition(ParseState *pstate,
  						  CreateStmtContext *cxt,
*************** static void transformFKConstraints(Parse
*** 114,119 ****
--- 122,128 ----
  static void transformConstraintAttrs(List *constraintList);
  static void transformColumnType(ParseState *pstate, ColumnDef *column);
  static void setSchemaName(char *context_schema, char **stmt_schema_name);
+ static DefaultACLsObject *mergeDefaultACLsObjects(DefaultACLsObject *a, DefaultACLsObject *b);
  
  
  /*
*************** setSchemaName(char *context_schema, char
*** 2115,2117 ****
--- 2124,2203 ----
  						"different from the one being created (%s)",
  						*stmt_schema_name, context_schema)));
  }
+ 
+ 
+ /* 
+  * transformDefaultACLsStmt
+  *		merge duplicate DefaultACLsObjects
+  *
+  *	We also check if we are setting default ACLs only for supported objects,
+  *	so that we can use functions from aclchk.c which allow more object types.
+  */
+ List *
+ transformDefaultACLsStmt(DefaultACLsStmt *stmt)
+ {
+ 	DefaultACLsStmtContext cxt;
+ 	ListCell   *object_cell;
+ 	List	   *result;
+ 
+ 	cxt.table = NULL;
+ 	cxt.view = NULL;
+ 	cxt.function = NULL;
+ 	cxt.sequence = NULL;
+ 
+ 	foreach(object_cell, stmt->objlist)
+ 	{
+ 		DefaultACLsObject *object = (DefaultACLsObject *) lfirst(object_cell);
+ 
+ 		switch (object->objtype)
+ 		{
+ 			case NSP_ACL_OBJ_RELATION:
+ 				cxt.table = mergeDefaultACLsObjects(cxt.table, object);
+ 				break;
+ 
+ 			case NSP_ACL_OBJ_VIEW:
+ 				cxt.view = mergeDefaultACLsObjects(cxt.view, object);
+ 				break;
+ 
+ 			case NSP_ACL_OBJ_FUNCTION:
+ 				cxt.function = mergeDefaultACLsObjects(cxt.function, object);
+ 				break;
+ 
+ 			case NSP_ACL_OBJ_SEQUENCE:
+ 				cxt.sequence = mergeDefaultACLsObjects(cxt.sequence, object);
+ 				break;
+ 
+ 			default:
+ 				elog(ERROR, "unrecognized objtype: %d",
+ 					 (int) object->objtype);
+ 		}
+ 	}
+ 
+ 	result = NIL;
+ 	result = lappend(result, cxt.table);
+ 	result = lappend(result, cxt.view);
+ 	result = lappend(result, cxt.function);
+ 	result = lappend(result, cxt.sequence);
+ 
+ 	return result;
+ }
+ 
+ 
+ static DefaultACLsObject*
+ mergeDefaultACLsObjects(DefaultACLsObject *a, DefaultACLsObject *b)
+ {
+ 	if (a == NULL)
+ 		return b;
+ 	if (b == NULL)
+ 		return a;
+ 
+ 	/* sanity checks */
+ 	if (a == b)
+ 		elog(ERROR, "cannot merge DefaultACLsObject to itself");
+ 
+ 	Assert(a->objtype == b->objtype) 
+ 
+ 	a->privileges = list_concat(a->privileges, b->privileges);
+ 
+ 	return a;
+ }
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index e6744bf..36716b2 100644
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
*************** check_xact_readonly(Node *parsetree)
*** 180,185 ****
--- 180,186 ----
  		case T_AlterOpFamilyStmt:
  		case T_RuleStmt:
  		case T_CreateSchemaStmt:
+ 		case T_DefaultACLsStmt:
  		case T_CreateSeqStmt:
  		case T_CreateStmt:
  		case T_CreateTableSpaceStmt:
*************** ProcessUtility(Node *parsetree,
*** 406,411 ****
--- 407,416 ----
  								queryString);
  			break;
  
+ 		case T_DefaultACLsStmt:
+ 			DefaultACLsCommand((DefaultACLsStmt *) parsetree);
+ 			break;
+ 
  		case T_CreateStmt:
  			{
  				List	   *stmts;
*************** CreateCommandTag(Node *parsetree)
*** 1362,1367 ****
--- 1367,1376 ----
  			tag = "CREATE SCHEMA";
  			break;
  
+ 		case T_DefaultACLsStmt:
+ 			tag = "ALTER SCHEMA";
+ 			break;
+ 
  		case T_CreateStmt:
  			tag = "CREATE TABLE";
  			break;
*************** GetCommandLogLevel(Node *parsetree)
*** 2131,2136 ****
--- 2140,2149 ----
  			lev = LOGSTMT_DDL;
  			break;
  
+ 		case T_DefaultACLsStmt:
+ 			lev = LOGSTMT_DDL;
+ 			break;
+ 
  		case T_CreateStmt:
  			lev = LOGSTMT_DDL;
  			break;
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index dbd3619..7c56b6f 100644
*** a/src/backend/utils/cache/syscache.c
--- b/src/backend/utils/cache/syscache.c
***************
*** 36,41 ****
--- 36,42 ----
  #include "catalog/pg_foreign_server.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_namespace.h"
+ #include "catalog/pg_namespace_default_acl.h"
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
  #include "catalog/pg_opfamily.h"
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index a2f6761..246a113 100644
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
*************** typedef enum ObjectClass
*** 146,151 ****
--- 146,152 ----
  	OCLASS_FDW,					/* pg_foreign_data_wrapper */
  	OCLASS_FOREIGN_SERVER,		/* pg_foreign_server */
  	OCLASS_USER_MAPPING,		/* pg_user_mapping */
+ 	OCLASS_NSPDEFACLS,			/* pg_namespace_default_acl */
  	MAX_OCLASS					/* MUST BE LAST */
  } ObjectClass;
  
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 81e18a1..a4b9d48 100644
*** a/src/include/catalog/indexing.h
--- b/src/include/catalog/indexing.h
*************** DECLARE_UNIQUE_INDEX(pg_user_mapping_oid
*** 267,272 ****
--- 267,278 ----
  DECLARE_UNIQUE_INDEX(pg_user_mapping_user_server_index, 175, on pg_user_mapping using btree(umuser oid_ops, umserver oid_ops));
  #define UserMappingUserServerIndexId	175
  
+ DECLARE_UNIQUE_INDEX(pg_namespace_default_acl_nspobj_index, 626, on pg_namespace_default_acl using btree(defaclnamespace oid_ops, defaclobjtype char_ops));
+ #define NamespaceDefaultAclNspObjIndexId	626
+ DECLARE_UNIQUE_INDEX(pg_namespace_default_acl_oid_index, 627, on pg_namespace_default_acl using btree(oid oid_ops));
+ #define NamespaceDefaultAclOidIndexId	627
+ 
+ 
  /* last step of initialization script: build the indexes declared above */
  BUILD_INDICES
  
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 0ed444c..6b7d05a 100644
*** a/src/include/catalog/pg_class.h
--- b/src/include/catalog/pg_class.h
*************** DESCR("");
*** 132,137 ****
--- 132,138 ----
  DATA(insert OID = 1259 (  pg_class		PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ ));
  DESCR("");
  
+ 
  #define		  RELKIND_INDEX			  'i'		/* secondary index */
  #define		  RELKIND_RELATION		  'r'		/* ordinary cataloged heap */
  #define		  RELKIND_SEQUENCE		  'S'		/* SEQUENCE relation */
diff --git a/src/include/catalog/pg_namespace_default_acl.h b/src/include/catalog/pg_namespace_default_acl.h
index ...e60a640 .
*** a/src/include/catalog/pg_namespace_default_acl.h
--- b/src/include/catalog/pg_namespace_default_acl.h
***************
*** 0 ****
--- 1,79 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_namespace_default_acl.h
+  *        definition of default ACLs for new objects created in schemas
+  *        Specified by schema and grantable object type
+  *
+  *
+  * Copyright (c) 2009, PostgreSQL Global Development Group
+  *
+  * $Id$
+  *
+  * NOTES
+  *	  the genbki.sh script reads this file and generates .bki
+  *	  information from the DATA() statements.
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef PG_NAMESPACE_DEFAULT_ACL_H
+ #define PG_NAMESPACE_DEFAULT_ACL_H
+ 
+ #include "catalog/genbki.h"
+ 
+ /* ----------------
+  *		pg_namespace_default_acl definition.  cpp turns this into
+  *		typedef struct FormData_pg_namespace_default_acl
+  * ----------------
+  */
+ #define NamespaceDefaultAclRelationId	1248
+ 
+ CATALOG(pg_namespace_default_acl,1248) /*BKI_BOOTSTRAP*/
+ {
+ 	Oid			defaclnamespace;	/* OID of namespace these ACLs apply to */
+ 	char		defaclobjtype;		/* see DEFACL_OBJECT_xxx constants below */
+ 
+ 	/*
+ 	 * VARIABLE LENGTH FIELDS start here.  These fields may be NULL, too.
+ 	 */
+ 
+ 	aclitem		defacllist[1];		/* Permissions to be applied at CREATE time */
+ } FormData_pg_namespace_default_acl;
+ 
+ /* Size of fixed part of pg_namespace_default_acl tuples, not counting var-length fields */
+ #define NAMESPACE_DEFAULT_ACL_TUPLE_SIZE \
+ 	 (offsetof(FormData_pg_namespace_default_acl,relfrozenxid) + sizeof(TransactionId))
+ 
+ /* ----------------
+  *		Form_pg_namespace_default_acl corresponds to a pointer to a tuple with
+  *		the format of pg_namespace_default_acl relation.
+  * ----------------
+  */
+ typedef FormData_pg_namespace_default_acl *Form_pg_namespace_default_acl;
+ 
+ /* ----------------
+  *		compiler constants for pg_namespace_default_acl
+  * ----------------
+  */
+ 
+ #define Natts_pg_namespace_default_acl					3
+ #define Anum_pg_namespace_default_acl_defaclnamespace			1
+ #define Anum_pg_namespace_default_acl_defaclgrantobjtype		2
+ #define Anum_pg_namespace_default_acl_defacldefacllist			3
+ 
+ /* ----------------
+  *		pg_namespace_default_acl has no initial contents
+  * ----------------
+  */
+ 
+ /*
+  * Types of objects which the user is allowed to specify default
+  * permissions on through pg_namespace_default_acl.
+  * Must have same value as relkind for objects stored id pg_class !
+  */
+ 
+ #define		  NSPDEFACLOBJ_TABLE	  'r'		/* table */
+ #define		  NSPDEFACLOBJ_VIEW		  'v'		/* view */
+ #define		  NSPDEFACLOBJ_FUNCTION	  'f'		/* function */
+ #define		  NSPDEFACLOBJ_SEQUENCE	  'S'		/* sequence */
+ 
+ #endif   /* PG_NAMESPACE_DEFAULT_ACL_H */
diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h
index 5f384a1..1067bee 100644
*** a/src/include/commands/schemacmds.h
--- b/src/include/commands/schemacmds.h
***************
*** 20,25 ****
--- 20,28 ----
  extern void CreateSchemaCommand(CreateSchemaStmt *parsetree,
  					const char *queryString);
  
+ extern void DefaultACLsCommand(DefaultACLsStmt *parsetree);
+ extern void RemoveDefaultACLsById(Oid nsdaOid);
+ 
  extern void RemoveSchemas(DropStmt *drop);
  extern void RemoveSchemaById(Oid schemaOid);
  
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 925375b..5ac8538 100644
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
*************** typedef enum NodeTag
*** 337,342 ****
--- 337,343 ----
  	T_CreateUserMappingStmt,
  	T_AlterUserMappingStmt,
  	T_DropUserMappingStmt,
+ 	T_DefaultACLsStmt,
  
  	/*
  	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
*************** typedef enum NodeTag
*** 376,381 ****
--- 377,385 ----
  	T_XmlSerialize,
  	T_WithClause,
  	T_CommonTableExpr,
+ 	T_DefaultACLsObject,
+ 	T_DefaultACLsPriv,
+ 
  
  	/*
  	 * TAGS FOR RANDOM OTHER STUFF
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a108b80..cd4821b 100644
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef enum DropBehavior
*** 1079,1084 ****
--- 1079,1085 ----
  	DROP_CASCADE				/* remove dependent objects too */
  } DropBehavior;
  
+ 
  /* ----------------------
   *	Alter Table
   * ----------------------
*************** typedef struct GrantRoleStmt
*** 1257,1262 ****
--- 1258,1300 ----
  	DropBehavior behavior;		/* drop behavior (for REVOKE) */
  } GrantRoleStmt;
  
+ 
+ /* ----------------------
+  *	Alter Schema DEFAULT PRIVILEGES
+  * ----------------------
+  */
+ typedef enum ACLSchemaObjectType
+ {
+ 	NSP_ACL_OBJ_RELATION,		/* table */
+ 	NSP_ACL_OBJ_VIEW,			/* view */
+ 	NSP_ACL_OBJ_FUNCTION,		/* function */
+ 	NSP_ACL_OBJ_SEQUENCE		/* sequence */
+ } ACLSchemaObjectType;
+ 
+ typedef struct DefaultACLsStmt
+ {
+ 	NodeTag		type;
+ 	char		*schemaname;
+ 	int			action;
+ 	List		*objlist;
+ } DefaultACLsStmt;
+ 
+ typedef struct DefaultACLsObject
+ {
+ 	NodeTag		type;
+ 	ACLSchemaObjectType objtype;
+ 	List	   *privileges;
+ } DefaultACLsObject;
+ 
+ typedef struct DefaultACLsPriv
+ {
+ 	NodeTag		type;
+ 	List	   *privileges;
+ 	List	   *grantees;
+ 	bool		grant_option;
+ } DefaultACLsPriv;
+ 
+ 
  /* ----------------------
   *		Copy Statement
   *
diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h
index 1fc3efd..98c13c4 100644
*** a/src/include/parser/parse_utilcmd.h
--- b/src/include/parser/parse_utilcmd.h
*************** extern IndexStmt *transformIndexStmt(Ind
*** 24,28 ****
--- 24,29 ----
  extern void transformRuleStmt(RuleStmt *stmt, const char *queryString,
  				  List **actions, Node **whereClause);
  extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
+ extern List *transformDefaultACLsStmt(DefaultACLsStmt *stmt);
  
  #endif   /* PARSE_UTILCMD_H */
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index bde8727..b12e590 100644
*** a/src/include/utils/acl.h
--- b/src/include/utils/acl.h
*************** extern Datum hash_aclitem(PG_FUNCTION_AR
*** 262,267 ****
--- 262,274 ----
   */
  extern void ExecuteGrantStmt(GrantStmt *stmt);
  extern void ExecGrantStmt_oids(InternalGrant *istmt);
+ extern AclMode string_to_privilege(const char *privname);
+ extern const char *privilege_to_string(AclMode privilege);
+ extern Acl *merge_acl_with_grant(Acl *old_acl, bool is_grant,
+ 					 bool grant_option, DropBehavior behavior,
+ 					 List *grantees, AclMode privileges,
+ 					 Oid grantorId, Oid ownerId);
+ 
  
  extern AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum,
  					 Oid roleid, AclMode mask, AclMaskHow how);
*************** extern bool pg_ts_dict_ownercheck(Oid di
*** 317,320 ****
--- 324,329 ----
  extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid);
  extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid);
  
+ extern Acl *pg_namespace_object_default_acl(Oid nsp_oid, char objtype, bool *isNull);
+ 
  #endif   /* ACL_H */
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index a17ff59..a606724 100644
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
*************** SELECT has_table_privilege('regressuser1
*** 815,822 ****
--- 815,933 ----
   t
  (1 row)
  
+ -- Default ACLs
+ \c -
+ CREATE SCHEMA regressns;
+ GRANT USAGE ON SCHEMA regressns TO regressgroup1, regressuser2;
+ -- bad input
+ ALTER SCHEMA regressns SET DEFAULT PRIVILEGES ON FUNCTION USAGE TO regressgroup1;
+ ERROR:  invalid privilege type USAGE for function
+ -- basic syntax
+ ALTER SCHEMA regressns SET DEFAULT PRIVILEGES ON TABLE SELECT TO public;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+   nspname  | defaclobjtype |               defacllist                
+ -----------+---------------+-----------------------------------------
+  regressns | r             | {postgres=arwdDxt/postgres,=r/postgres}
+ (1 row)
+ 
+ ALTER SCHEMA regressns SET DEFAULT PRIVILEGES ON TABLE SELECT TO regressgroup1, regressuser2 AND UPDATE TO regressuser2 AND INSERT, DELETE TO regressuser2;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+   nspname  | defaclobjtype |                                   defacllist                                    
+ -----------+---------------+---------------------------------------------------------------------------------
+  regressns | r             | {postgres=arwdDxt/postgres,regressgroup1=r/postgres,regressuser2=arwd/postgres}
+ (1 row)
+ 
+ ALTER SCHEMA regressns ADD DEFAULT PRIVILEGES ON TABLE INSERT TO regressgroup1;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+   nspname  | defaclobjtype |                                    defacllist                                    
+ -----------+---------------+----------------------------------------------------------------------------------
+  regressns | r             | {postgres=arwdDxt/postgres,regressgroup1=ar/postgres,regressuser2=arwd/postgres}
+ (1 row)
+ 
+ ALTER SCHEMA regressns DROP DEFAULT PRIVILEGES ON TABLE DELETE FROM regressuser2;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+   nspname  | defaclobjtype |                                   defacllist                                    
+ -----------+---------------+---------------------------------------------------------------------------------
+  regressns | r             | {postgres=arwdDxt/postgres,regressgroup1=ar/postgres,regressuser2=arw/postgres}
+ (1 row)
+ 
+ -- objects created with proper permissions
+ ALTER SCHEMA regressns SET DEFAULT PRIVILEGES 
+     ON TABLE SELECT TO regressgroup1, regressuser2 AND UPDATE,INSERT,DELETE TO regressuser2
+     ON VIEW  SELECT TO regressgroup1 AND ALL PRIVILEGES TO regressuser2 WITH GRANT OPTION
+     ON SEQUENCE ALL TO regressgroup1, regressuser2
+     ON FUNCTION EXECUTE TO regressgroup1;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+   nspname  | defaclobjtype |                                        defacllist                                         
+ -----------+---------------+-------------------------------------------------------------------------------------------
+  regressns | S             | {postgres=arwdDxt/postgres,regressgroup1=rwU/postgres,regressuser2=rwU/postgres}
+  regressns | f             | {postgres=arwdDxt/postgres,regressgroup1=X/postgres}
+  regressns | r             | {postgres=arwdDxt/postgres,regressgroup1=r/postgres,regressuser2=arwd/postgres}
+  regressns | v             | {postgres=arwdDxt/postgres,regressgroup1=r/postgres,regressuser2=a*r*w*d*D*x*t*/postgres}
+ (4 rows)
+ 
+ CREATE TABLE regressns.acltest1 (a serial, b text);
+ NOTICE:  CREATE TABLE will create implicit sequence "acltest1_a_seq" for serial column "acltest1.a"
+ SELECT has_table_privilege('regressgroup1', 'regressns.acltest1', 'INSERT'); -- false
+  has_table_privilege 
+ ---------------------
+  f
+ (1 row)
+ 
+ SELECT has_table_privilege('regressuser2', 'regressns.acltest1', 'INSERT'); -- true
+  has_table_privilege 
+ ---------------------
+  t
+ (1 row)
+ 
+ SELECT relname, relacl FROM pg_class WHERE relname = 'acltest1';
+  relname  |                                     relacl                                      
+ ----------+---------------------------------------------------------------------------------
+  acltest1 | {postgres=arwdDxt/postgres,regressgroup1=r/postgres,regressuser2=arwd/postgres}
+ (1 row)
+ 
+ ALTER SCHEMA regressns DROP DEFAULT PRIVILEGES ON TABLE ALL FROM regressuser2;
+ CREATE TABLE regressns.acltest2 (a int);
+ SELECT has_table_privilege('regressuser2', 'regressns.acltest2', 'INSERT'); -- false
+  has_table_privilege 
+ ---------------------
+  f
+ (1 row)
+ 
+ SELECT relname, relacl FROM pg_class WHERE relname = 'acltest2';
+  relname  |                        relacl                        
+ ----------+------------------------------------------------------
+  acltest2 | {postgres=arwdDxt/postgres,regressgroup1=r/postgres}
+ (1 row)
+ 
+ CREATE FUNCTION regressns.testfunc1() RETURNS int AS 'select 1;' LANGUAGE sql;
+ SELECT has_function_privilege('regressgroup1', 'regressns.testfunc1()', 'EXECUTE'); -- true
+  has_function_privilege 
+ ------------------------
+  t
+ (1 row)
+ 
+ CREATE VIEW regressns.acltest3 AS SELECT * FROM regressns.acltest1;
+ SET SESSION AUTHORIZATION regressuser2;
+ GRANT SELECT ON regressns.acltest3 TO regressuser1;
+ SELECT has_table_privilege('regressuser1', 'regressns.acltest3', 'SELECT'); -- true
+  has_table_privilege 
+ ---------------------
+  t
+ (1 row)
+ 
  -- clean up
  \c
+ DROP SCHEMA regressns CASCADE;
+ NOTICE:  drop cascades to 8 other objects
+ DETAIL:  drop cascades to default acls in namespace regressns for new TABLE
+ drop cascades to default acls in namespace regressns for new VIEW
+ drop cascades to default acls in namespace regressns for new SEQUENCE
+ drop cascades to default acls in namespace regressns for new FUNCTION
+ drop cascades to table regressns.acltest1
+ drop cascades to table regressns.acltest2
+ drop cascades to function regressns.testfunc1()
+ drop cascades to view regressns.acltest3
  DROP FUNCTION testfunc2(int);
  DROP FUNCTION testfunc4(boolean);
  DROP VIEW atestv1;
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index c6f1f15..37411f6 100644
*** a/src/test/regress/expected/sanity_check.out
--- b/src/test/regress/expected/sanity_check.out
*************** SELECT relname, relhasindex
*** 9,157 ****
     FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = relnamespace
     WHERE relkind = 'r' AND (nspname ~ '^pg_temp_') IS NOT TRUE
     ORDER BY relname;
!          relname         | relhasindex 
! -------------------------+-------------
!  a                       | f
!  a_star                  | f
!  abstime_tbl             | f
!  aggtest                 | f
!  array_index_op_test     | t
!  array_op_test           | f
!  b                       | f
!  b_star                  | f
!  box_tbl                 | f
!  bprime                  | f
!  bt_f8_heap              | t
!  bt_i4_heap              | t
!  bt_name_heap            | t
!  bt_txt_heap             | t
!  c                       | f
!  c_star                  | f
!  char_tbl                | f
!  check2_tbl              | f
!  check_tbl               | f
!  circle_tbl              | t
!  city                    | f
!  copy_tbl                | f
!  d                       | f
!  d_star                  | f
!  date_tbl                | f
!  default_tbl             | f
!  defaultexpr_tbl         | f
!  dept                    | f
!  e_star                  | f
!  emp                     | f
!  equipment_r             | f
!  f_star                  | f
!  fast_emp4000            | t
!  float4_tbl              | f
!  float8_tbl              | f
!  func_index_heap         | t
!  hash_f8_heap            | t
!  hash_i4_heap            | t
!  hash_name_heap          | t
!  hash_txt_heap           | t
!  hobbies_r               | f
!  ihighway                | t
!  inet_tbl                | f
!  inhe                    | f
!  inhf                    | f
!  inhx                    | t
!  insert_tbl              | f
!  int2_tbl                | f
!  int4_tbl                | f
!  int8_tbl                | f
!  interval_tbl            | f
!  iportaltest             | f
!  log_table               | f
!  lseg_tbl                | f
!  main_table              | f
!  money_data              | f
!  num_data                | f
!  num_exp_add             | t
!  num_exp_div             | t
!  num_exp_ln              | t
!  num_exp_log10           | t
!  num_exp_mul             | t
!  num_exp_power_10_ln     | t
!  num_exp_sqrt            | t
!  num_exp_sub             | t
!  num_input_test          | f
!  num_result              | f
!  onek                    | t
!  onek2                   | t
!  path_tbl                | f
!  person                  | f
!  pg_aggregate            | t
!  pg_am                   | t
!  pg_amop                 | t
!  pg_amproc               | t
!  pg_attrdef              | t
!  pg_attribute            | t
!  pg_auth_members         | t
!  pg_authid               | t
!  pg_cast                 | t
!  pg_class                | t
!  pg_constraint           | t
!  pg_conversion           | t
!  pg_database             | t
!  pg_depend               | t
!  pg_description          | t
!  pg_enum                 | t
!  pg_foreign_data_wrapper | t
!  pg_foreign_server       | t
!  pg_index                | t
!  pg_inherits             | t
!  pg_language             | t
!  pg_largeobject          | t
!  pg_listener             | f
!  pg_namespace            | t
!  pg_opclass              | t
!  pg_operator             | t
!  pg_opfamily             | t
!  pg_pltemplate           | t
!  pg_proc                 | t
!  pg_rewrite              | t
!  pg_shdepend             | t
!  pg_shdescription        | t
!  pg_statistic            | t
!  pg_tablespace           | t
!  pg_trigger              | t
!  pg_ts_config            | t
!  pg_ts_config_map        | t
!  pg_ts_dict              | t
!  pg_ts_parser            | t
!  pg_ts_template          | t
!  pg_type                 | t
!  pg_user_mapping         | t
!  point_tbl               | f
!  polygon_tbl             | t
!  ramp                    | f
!  real_city               | f
!  reltime_tbl             | f
!  road                    | t
!  shighway                | t
!  slow_emp4000            | f
!  sql_features            | f
!  sql_implementation_info | f
!  sql_languages           | f
!  sql_packages            | f
!  sql_parts               | f
!  sql_sizing              | f
!  sql_sizing_profiles     | f
!  stud_emp                | f
!  student                 | f
!  tenk1                   | t
!  tenk2                   | t
!  test_tsvector           | f
!  text_tbl                | f
!  time_tbl                | f
!  timestamp_tbl           | f
!  timestamptz_tbl         | f
!  timetz_tbl              | f
!  tinterval_tbl           | f
!  varchar_tbl             | f
! (140 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
--- 9,158 ----
     FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = relnamespace
     WHERE relkind = 'r' AND (nspname ~ '^pg_temp_') IS NOT TRUE
     ORDER BY relname;
!          relname          | relhasindex 
! --------------------------+-------------
!  a                        | f
!  a_star                   | f
!  abstime_tbl              | f
!  aggtest                  | f
!  array_index_op_test      | t
!  array_op_test            | f
!  b                        | f
!  b_star                   | f
!  box_tbl                  | f
!  bprime                   | f
!  bt_f8_heap               | t
!  bt_i4_heap               | t
!  bt_name_heap             | t
!  bt_txt_heap              | t
!  c                        | f
!  c_star                   | f
!  char_tbl                 | f
!  check2_tbl               | f
!  check_tbl                | f
!  circle_tbl               | t
!  city                     | f
!  copy_tbl                 | f
!  d                        | f
!  d_star                   | f
!  date_tbl                 | f
!  default_tbl              | f
!  defaultexpr_tbl          | f
!  dept                     | f
!  e_star                   | f
!  emp                      | f
!  equipment_r              | f
!  f_star                   | f
!  fast_emp4000             | t
!  float4_tbl               | f
!  float8_tbl               | f
!  func_index_heap          | t
!  hash_f8_heap             | t
!  hash_i4_heap             | t
!  hash_name_heap           | t
!  hash_txt_heap            | t
!  hobbies_r                | f
!  ihighway                 | t
!  inet_tbl                 | f
!  inhe                     | f
!  inhf                     | f
!  inhx                     | t
!  insert_tbl               | f
!  int2_tbl                 | f
!  int4_tbl                 | f
!  int8_tbl                 | f
!  interval_tbl             | f
!  iportaltest              | f
!  log_table                | f
!  lseg_tbl                 | f
!  main_table               | f
!  money_data               | f
!  num_data                 | f
!  num_exp_add              | t
!  num_exp_div              | t
!  num_exp_ln               | t
!  num_exp_log10            | t
!  num_exp_mul              | t
!  num_exp_power_10_ln      | t
!  num_exp_sqrt             | t
!  num_exp_sub              | t
!  num_input_test           | f
!  num_result               | f
!  onek                     | t
!  onek2                    | t
!  path_tbl                 | f
!  person                   | f
!  pg_aggregate             | t
!  pg_am                    | t
!  pg_amop                  | t
!  pg_amproc                | t
!  pg_attrdef               | t
!  pg_attribute             | t
!  pg_auth_members          | t
!  pg_authid                | t
!  pg_cast                  | t
!  pg_class                 | t
!  pg_constraint            | t
!  pg_conversion            | t
!  pg_database              | t
!  pg_depend                | t
!  pg_description           | t
!  pg_enum                  | t
!  pg_foreign_data_wrapper  | t
!  pg_foreign_server        | t
!  pg_index                 | t
!  pg_inherits              | t
!  pg_language              | t
!  pg_largeobject           | t
!  pg_listener              | f
!  pg_namespace             | t
!  pg_namespace_default_acl | t
!  pg_opclass               | t
!  pg_operator              | t
!  pg_opfamily              | t
!  pg_pltemplate            | t
!  pg_proc                  | t
!  pg_rewrite               | t
!  pg_shdepend              | t
!  pg_shdescription         | t
!  pg_statistic             | t
!  pg_tablespace            | t
!  pg_trigger               | t
!  pg_ts_config             | t
!  pg_ts_config_map         | t
!  pg_ts_dict               | t
!  pg_ts_parser             | t
!  pg_ts_template           | t
!  pg_type                  | t
!  pg_user_mapping          | t
!  point_tbl                | f
!  polygon_tbl              | t
!  ramp                     | f
!  real_city                | f
!  reltime_tbl              | f
!  road                     | t
!  shighway                 | t
!  slow_emp4000             | f
!  sql_features             | f
!  sql_implementation_info  | f
!  sql_languages            | f
!  sql_packages             | f
!  sql_parts                | f
!  sql_sizing               | f
!  sql_sizing_profiles      | f
!  stud_emp                 | f
!  student                  | f
!  tenk1                    | t
!  tenk2                    | t
!  test_tsvector            | f
!  text_tbl                 | f
!  time_tbl                 | f
!  timestamp_tbl            | f
!  timestamptz_tbl          | f
!  timetz_tbl               | f
!  tinterval_tbl            | f
!  varchar_tbl              | f
! (141 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 5aa1012..05cb74f 100644
*** a/src/test/regress/sql/privileges.sql
--- b/src/test/regress/sql/privileges.sql
*************** SELECT has_table_privilege('regressuser3
*** 469,478 ****
--- 469,532 ----
  SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true
  
  
+ -- Default ACLs
+ 
+ \c -
+ 
+ CREATE SCHEMA regressns;
+ GRANT USAGE ON SCHEMA regressns TO regressgroup1, regressuser2;
+ 
+ -- bad input
+ 
+ ALTER SCHEMA regressns SET DEFAULT PRIVILEGES ON FUNCTION USAGE TO regressgroup1;
+ 
+ -- basic syntax
+ 
+ ALTER SCHEMA regressns SET DEFAULT PRIVILEGES ON TABLE SELECT TO public;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+ 
+ ALTER SCHEMA regressns SET DEFAULT PRIVILEGES ON TABLE SELECT TO regressgroup1, regressuser2 AND UPDATE TO regressuser2 AND INSERT, DELETE TO regressuser2;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+ 
+ ALTER SCHEMA regressns ADD DEFAULT PRIVILEGES ON TABLE INSERT TO regressgroup1;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+ 
+ ALTER SCHEMA regressns DROP DEFAULT PRIVILEGES ON TABLE DELETE FROM regressuser2;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+ 
+ -- objects created with proper permissions
+ 
+ ALTER SCHEMA regressns SET DEFAULT PRIVILEGES 
+     ON TABLE SELECT TO regressgroup1, regressuser2 AND UPDATE,INSERT,DELETE TO regressuser2
+     ON VIEW  SELECT TO regressgroup1 AND ALL PRIVILEGES TO regressuser2 WITH GRANT OPTION
+     ON SEQUENCE ALL TO regressgroup1, regressuser2
+     ON FUNCTION EXECUTE TO regressgroup1;
+ SELECT (SELECT nspname FROM pg_namespace WHERE oid = defaclnamespace) AS nspname, defaclobjtype, defacllist FROM pg_namespace_default_acl ORDER BY 1, 2;
+ 
+ CREATE TABLE regressns.acltest1 (a serial, b text);
+ SELECT has_table_privilege('regressgroup1', 'regressns.acltest1', 'INSERT'); -- false
+ SELECT has_table_privilege('regressuser2', 'regressns.acltest1', 'INSERT'); -- true
+ SELECT relname, relacl FROM pg_class WHERE relname = 'acltest1';
+ 
+ ALTER SCHEMA regressns DROP DEFAULT PRIVILEGES ON TABLE ALL FROM regressuser2;
+ CREATE TABLE regressns.acltest2 (a int);
+ SELECT has_table_privilege('regressuser2', 'regressns.acltest2', 'INSERT'); -- false
+ SELECT relname, relacl FROM pg_class WHERE relname = 'acltest2';
+ 
+ CREATE FUNCTION regressns.testfunc1() RETURNS int AS 'select 1;' LANGUAGE sql;
+ SELECT has_function_privilege('regressgroup1', 'regressns.testfunc1()', 'EXECUTE'); -- true
+ 
+ CREATE VIEW regressns.acltest3 AS SELECT * FROM regressns.acltest1;
+ SET SESSION AUTHORIZATION regressuser2;
+ GRANT SELECT ON regressns.acltest3 TO regressuser1;
+ SELECT has_table_privilege('regressuser1', 'regressns.acltest3', 'SELECT'); -- true
+ 
  -- clean up
  
  \c
  
+ DROP SCHEMA regressns CASCADE;
+ 
  DROP FUNCTION testfunc2(int);
  DROP FUNCTION testfunc4(boolean);
  
