*** a/src/backend/bootstrap/bootparse.y
--- b/src/backend/bootstrap/bootparse.y
***************
*** 247,254 **** Boot_CreateStmt:
  													  ONCOMMIT_NOOP,
  													  (Datum) 0,
  													  false,
! 													  true,
! 													  false);
  						elog(DEBUG4, "relation created with oid %u", id);
  					}
  					do_end();
--- 247,253 ----
  													  ONCOMMIT_NOOP,
  													  (Datum) 0,
  													  false,
! 													  true);
  						elog(DEBUG4, "relation created with oid %u", id);
  					}
  					do_end();
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 973,980 **** heap_create_with_catalog(const char *relname,
  						 OnCommitAction oncommit,
  						 Datum reloptions,
  						 bool use_user_acl,
! 						 bool allow_system_table_mods,
! 						 bool if_not_exists)
  {
  	Relation	pg_class_desc;
  	Relation	new_rel_desc;
--- 973,979 ----
  						 OnCommitAction oncommit,
  						 Datum reloptions,
  						 bool use_user_acl,
! 						 bool allow_system_table_mods)
  {
  	Relation	pg_class_desc;
  	Relation	new_rel_desc;
***************
*** 994,1019 **** heap_create_with_catalog(const char *relname,
  	CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods);
  
  	/*
! 	 * If the relation already exists, it's an error, unless the user
! 	 * specifies "IF NOT EXISTS".  In that case, we just print a notice and do
! 	 * nothing further.
  	 */
  	existing_relid = get_relname_relid(relname, relnamespace);
  	if (existing_relid != InvalidOid)
- 	{
- 		if (if_not_exists)
- 		{
- 			ereport(NOTICE,
- 					(errcode(ERRCODE_DUPLICATE_TABLE),
- 					 errmsg("relation \"%s\" already exists, skipping",
- 							relname)));
- 			heap_close(pg_class_desc, RowExclusiveLock);
- 			return InvalidOid;
- 		}
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_TABLE),
  				 errmsg("relation \"%s\" already exists", relname)));
- 	}
  
  	/*
  	 * Since we are going to create a rowtype as well, also check for
--- 993,1006 ----
  	CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods);
  
  	/*
! 	 * This would fail later on anyway, if the relation already exists.  But
! 	 * by catching it here we can emit a nicer error message.
  	 */
  	existing_relid = get_relname_relid(relname, relnamespace);
  	if (existing_relid != InvalidOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_TABLE),
  				 errmsg("relation \"%s\" already exists", relname)));
  
  	/*
  	 * Since we are going to create a rowtype as well, also check for
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
***************
*** 361,366 **** RangeVarGetCreationNamespace(const RangeVar *newRelation)
--- 361,395 ----
  }
  
  /*
+  * RangeVarGetAndCheckCreationNamespace
+  *      As RangeVarGetCreationNamespace, but with a permissions check.
+  */
+ Oid
+ RangeVarGetAndCheckCreationNamespace(const RangeVar *newRelation)
+ {
+ 	Oid			namespaceId;
+ 
+ 	namespaceId = RangeVarGetCreationNamespace(newRelation);
+ 
+ 	/*
+ 	 * Check we have permission to create there. Skip check if bootstrapping,
+ 	 * since permissions machinery may not be working yet.
+ 	 */
+ 	if (!IsBootstrapProcessingMode())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
+ 										  ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(namespaceId));
+ 	}
+ 
+ 	return namespaceId;
+ }
+ 
+ /*
   * RelnameGetRelid
   *		Try to resolve an unqualified relation name.
   *		Returns OID if relation found in search path, else InvalidOid.
*** a/src/backend/catalog/toasting.c
--- b/src/backend/catalog/toasting.c
***************
*** 226,233 **** create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
  										   ONCOMMIT_NOOP,
  										   reloptions,
  										   false,
! 										   true,
! 										   false);
  	Assert(toast_relid != InvalidOid);
  
  	/* make the toast relation visible, else heap_open will fail */
--- 226,232 ----
  										   ONCOMMIT_NOOP,
  										   reloptions,
  										   false,
! 										   true);
  	Assert(toast_relid != InvalidOid);
  
  	/* make the toast relation visible, else heap_open will fail */
*** a/src/backend/commands/cluster.c
--- b/src/backend/commands/cluster.c
***************
*** 646,653 **** make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
  										  ONCOMMIT_NOOP,
  										  reloptions,
  										  false,
! 										  true,
! 										  false);
  	Assert(OIDNewHeap != InvalidOid);
  
  	ReleaseSysCache(tuple);
--- 646,652 ----
  										  ONCOMMIT_NOOP,
  										  reloptions,
  										  false,
! 										  true);
  	Assert(OIDNewHeap != InvalidOid);
  
  	ReleaseSysCache(tuple);
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 439,460 **** DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
  				 errmsg("cannot create temporary table within security-restricted operation")));
  
  	/*
! 	 * Look up the namespace in which we are supposed to create the relation.
! 	 * Check we have permission to create there. Skip check if bootstrapping,
! 	 * since permissions machinery may not be working yet.
  	 */
! 	namespaceId = RangeVarGetCreationNamespace(stmt->relation);
! 
! 	if (!IsBootstrapProcessingMode())
! 	{
! 		AclResult	aclresult;
! 
! 		aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
! 										  ACL_CREATE);
! 		if (aclresult != ACLCHECK_OK)
! 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 						   get_namespace_name(namespaceId));
! 	}
  
  	/*
  	 * Select tablespace to use.  If not specified, use default tablespace
--- 439,448 ----
  				 errmsg("cannot create temporary table within security-restricted operation")));
  
  	/*
! 	 * Look up the namespace in which we are supposed to create the relation,
! 	 * and check we have permission to create there.
  	 */
! 	namespaceId = RangeVarGetAndCheckCreationNamespace(stmt->relation);
  
  	/*
  	 * Select tablespace to use.  If not specified, use default tablespace
***************
*** 602,617 **** DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
  										  stmt->oncommit,
  										  reloptions,
  										  true,
! 										  allowSystemTableMods,
! 										  stmt->if_not_exists);
! 
! 	/*
! 	 * If heap_create_with_catalog returns InvalidOid, it means that the user
! 	 * specified "IF NOT EXISTS" and the relation already exists.  In that
! 	 * case we do nothing further.
! 	 */
! 	if (relationId == InvalidOid)
! 		return InvalidOid;
  
  	/* Store inheritance information for new rel. */
  	StoreCatalogInheritance(relationId, inheritOids);
--- 590,596 ----
  										  stmt->oncommit,
  										  reloptions,
  										  true,
! 										  allowSystemTableMods);
  
  	/* Store inheritance information for new rel. */
  	StoreCatalogInheritance(relationId, inheritOids);
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***************
*** 2341,2347 **** OpenIntoRel(QueryDesc *queryDesc)
  	Oid			namespaceId;
  	Oid			tablespaceId;
  	Datum		reloptions;
- 	AclResult	aclresult;
  	Oid			intoRelationId;
  	TupleDesc	tupdesc;
  	DR_intorel *myState;
--- 2341,2346 ----
***************
*** 2378,2390 **** OpenIntoRel(QueryDesc *queryDesc)
  	 * Find namespace to create in, check its permissions
  	 */
  	intoName = into->rel->relname;
! 	namespaceId = RangeVarGetCreationNamespace(into->rel);
! 
! 	aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
! 									  ACL_CREATE);
! 	if (aclresult != ACLCHECK_OK)
! 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 					   get_namespace_name(namespaceId));
  
  	/*
  	 * Select tablespace to use.  If not specified, use default tablespace
--- 2377,2383 ----
  	 * Find namespace to create in, check its permissions
  	 */
  	intoName = into->rel->relname;
! 	namespaceId = RangeVarGetAndCheckCreationNamespace(into->rel);
  
  	/*
  	 * Select tablespace to use.  If not specified, use default tablespace
***************
*** 2444,2451 **** OpenIntoRel(QueryDesc *queryDesc)
  											  into->onCommit,
  											  reloptions,
  											  true,
! 											  allowSystemTableMods,
! 											  false);
  	Assert(intoRelationId != InvalidOid);
  
  	FreeTupleDesc(tupdesc);
--- 2437,2443 ----
  											  into->onCommit,
  											  reloptions,
  											  true,
! 											  allowSystemTableMods);
  	Assert(intoRelationId != InvalidOid);
  
  	FreeTupleDesc(tupdesc);
*** a/src/backend/parser/parse_utilcmd.c
--- b/src/backend/parser/parse_utilcmd.c
***************
*** 148,153 **** transformCreateStmt(CreateStmt *stmt, const char *queryString)
--- 148,154 ----
  	List	   *result;
  	List	   *save_alist;
  	ListCell   *elements;
+ 	Oid			namespaceid;
  
  	/*
  	 * We must not scribble on the passed-in CreateStmt, so copy it.  (This is
***************
*** 156,161 **** transformCreateStmt(CreateStmt *stmt, const char *queryString)
--- 157,189 ----
  	stmt = (CreateStmt *) copyObject(stmt);
  
  	/*
+ 	 * Look up the creation namespace.  This also checks permissions on the
+ 	 * target namespace, so that we throw any permissions error as early as
+ 	 * possible.
+ 	 */
+ 	namespaceid = RangeVarGetAndCheckCreationNamespace(stmt->relation);
+ 
+ 	/*
+ 	 * If the relation already exists and the user specified "IF NOT EXISTS",
+ 	 * bail out with a NOTICE.
+ 	 */
+ 	if (stmt->if_not_exists)
+ 	{
+ 		Oid		existing_relid;
+ 
+ 		existing_relid = get_relname_relid(stmt->relation->relname,
+ 										   namespaceid);
+ 		if (existing_relid != InvalidOid)
+ 		{
+ 			ereport(NOTICE,
+ 					(errcode(ERRCODE_DUPLICATE_TABLE),
+ 					 errmsg("relation \"%s\" already exists, skipping",
+ 						 stmt->relation->relname)));
+ 			return NIL;
+ 		}
+ 	}
+ 
+ 	/*
  	 * If the target relation name isn't schema-qualified, make it so.  This
  	 * prevents some corner cases in which added-on rewritten commands might
  	 * think they should apply to other relations that have the same name and
***************
*** 164,174 **** transformCreateStmt(CreateStmt *stmt, const char *queryString)
  	 */
  	if (stmt->relation->schemaname == NULL
  		&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
- 	{
- 		Oid			namespaceid = RangeVarGetCreationNamespace(stmt->relation);
- 
  		stmt->relation->schemaname = get_namespace_name(namespaceid);
- 	}
  
  	/* Set up pstate and CreateStmtContext */
  	pstate = make_parsestate(NULL);
--- 192,198 ----
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 530,542 **** standard_ProcessUtility(Node *parsetree,
  												InvalidOid);
  
  						/*
- 						 * If "IF NOT EXISTS" was specified and the relation
- 						 * already exists, do nothing further.
- 						 */
- 						if (relOid == InvalidOid)
- 							continue;
- 
- 						/*
  						 * Let AlterTableCreateToastTable decide if this one
  						 * needs a secondary relation too.
  						 */
--- 530,535 ----
***************
*** 559,573 **** standard_ProcessUtility(Node *parsetree,
  						relOid = DefineRelation((CreateStmt *) stmt,
  												RELKIND_FOREIGN_TABLE,
  												InvalidOid);
! 
! 						/*
! 						 * Unless "IF NOT EXISTS" was specified and the
! 						 * relation already exists, create the
! 						 * pg_foreign_table entry.
! 						 */
! 						if (relOid != InvalidOid)
! 							CreateForeignTable((CreateForeignTableStmt *) stmt,
! 											   relOid);
  					}
  					else
  					{
--- 552,559 ----
  						relOid = DefineRelation((CreateStmt *) stmt,
  												RELKIND_FOREIGN_TABLE,
  												InvalidOid);
! 						CreateForeignTable((CreateForeignTableStmt *) stmt,
! 										   relOid);
  					}
  					else
  					{
*** a/src/include/catalog/heap.h
--- b/src/include/catalog/heap.h
***************
*** 63,70 **** extern Oid heap_create_with_catalog(const char *relname,
  						 OnCommitAction oncommit,
  						 Datum reloptions,
  						 bool use_user_acl,
! 						 bool allow_system_table_mods,
! 						 bool if_not_exists);
  
  extern void heap_drop_with_catalog(Oid relid);
  
--- 63,69 ----
  						 OnCommitAction oncommit,
  						 Datum reloptions,
  						 bool use_user_acl,
! 						 bool allow_system_table_mods);
  
  extern void heap_drop_with_catalog(Oid relid);
  
*** a/src/include/catalog/namespace.h
--- b/src/include/catalog/namespace.h
***************
*** 49,54 **** typedef struct OverrideSearchPath
--- 49,55 ----
  
  extern Oid	RangeVarGetRelid(const RangeVar *relation, bool failOK);
  extern Oid	RangeVarGetCreationNamespace(const RangeVar *newRelation);
+ extern Oid	RangeVarGetAndCheckCreationNamespace(const RangeVar *newRelation);
  extern Oid	RelnameGetRelid(const char *relname);
  extern bool RelationIsVisible(Oid relid);
  
