create-table-like-comment-fix.patch

text/x-patch

Filename: create-table-like-comment-fix.patch
Type: text/x-patch
Part: 0
Message: Getting rid of pre-assignment of index names in CREATE TABLE LIKE

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/bootstrap/bootparse.y 0 0
src/backend/commands/indexcmds.c 0 0
src/backend/commands/tablecmds.c 0 0
src/backend/nodes/copyfuncs.c 0 0
src/backend/nodes/equalfuncs.c 0 0
src/backend/nodes/outfuncs.c 0 0
src/backend/parser/gram.y 0 0
src/backend/parser/parse_utilcmd.c 0 0
src/backend/tcop/utility.c 0 0
src/include/commands/defrem.h 0 0
src/include/nodes/parsenodes.h 0 0
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 18f0add852e7832739e3877811e385abcb540fab..ec634f1660e0be883b451abbb380d6dc30e69b93 100644
*** a/src/backend/bootstrap/bootparse.y
--- b/src/backend/bootstrap/bootparse.y
*************** Boot_InsertStmt:
*** 279,296 ****
  Boot_DeclareIndexStmt:
  		  XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
  				{
  					do_start();
  
! 					DefineIndex(makeRangeVar(NULL, $6, -1),
! 								$3,
  								$4,
! 								InvalidOid,
! 								$8,
! 								NULL,
! 								$10,
! 								NULL, NIL, NIL,
! 								false, false, false, false, false,
! 								false, false, true, false, false);
  					do_end();
  				}
  		;
--- 279,312 ----
  Boot_DeclareIndexStmt:
  		  XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
  				{
+ 					IndexStmt *stmt = makeNode(IndexStmt);
+ 
  					do_start();
  
! 					stmt->idxname = $3;
! 					stmt->relation = makeRangeVar(NULL, $6, -1);
! 					stmt->accessMethod = $8;
! 					stmt->tableSpace = NULL;
! 					stmt->indexParams = $10;
! 					stmt->options = NIL;
! 					stmt->whereClause = NULL;
! 					stmt->excludeOpNames = NIL;
! 					stmt->idxcomment = NULL;
! 					stmt->indexOid = InvalidOid;
! 					stmt->oldNode = InvalidOid;
! 					stmt->unique = false;
! 					stmt->primary = false;
! 					stmt->isconstraint = false;
! 					stmt->deferrable = false;
! 					stmt->initdeferred = false;
! 					stmt->concurrent = false;
! 
! 					DefineIndex(stmt,
  								$4,
! 								false,
! 								false,
! 								true, /* skip_build */
! 								false);
  					do_end();
  				}
  		;
*************** Boot_DeclareIndexStmt:
*** 298,315 ****
  Boot_DeclareUniqueIndexStmt:
  		  XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
  				{
  					do_start();
  
! 					DefineIndex(makeRangeVar(NULL, $7, -1),
! 								$4,
  								$5,
! 								InvalidOid,
! 								$9,
! 								NULL,
! 								$11,
! 								NULL, NIL, NIL,
! 								true, false, false, false, false,
! 								false, false, true, false, false);
  					do_end();
  				}
  		;
--- 314,347 ----
  Boot_DeclareUniqueIndexStmt:
  		  XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
  				{
+ 					IndexStmt *stmt = makeNode(IndexStmt);
+ 
  					do_start();
  
! 					stmt->idxname = $4;
! 					stmt->relation = makeRangeVar(NULL, $7, -1);
! 					stmt->accessMethod = $9;
! 					stmt->tableSpace = NULL;
! 					stmt->indexParams = $11;
! 					stmt->options = NIL;
! 					stmt->whereClause = NULL;
! 					stmt->excludeOpNames = NIL;
! 					stmt->idxcomment = NULL;
! 					stmt->indexOid = InvalidOid;
! 					stmt->oldNode = InvalidOid;
! 					stmt->unique = true;
! 					stmt->primary = false;
! 					stmt->isconstraint = false;
! 					stmt->deferrable = false;
! 					stmt->initdeferred = false;
! 					stmt->concurrent = false;
! 
! 					DefineIndex(stmt,
  								$5,
! 								false,
! 								false,
! 								true, /* skip_build */
! 								false);
  					do_end();
  				}
  		;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index e5d1d8b699ad6d37cd3dd9e19b1d76ba97c01eaa..f315ab60154d6c6aa3c96f05babb8e79945f70b8 100644
*** a/src/backend/commands/indexcmds.c
--- b/src/backend/commands/indexcmds.c
***************
*** 24,29 ****
--- 24,30 ----
  #include "catalog/pg_opfamily.h"
  #include "catalog/pg_tablespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/comment.h"
  #include "commands/dbcommands.h"
  #include "commands/defrem.h"
  #include "commands/tablecmds.h"
*************** static void ComputeIndexAttrs(IndexInfo 
*** 65,71 ****
--- 66,76 ----
  				  bool isconstraint);
  static Oid GetIndexOpClass(List *opclass, Oid attrType,
  				char *accessMethodName, Oid accessMethodId);
+ static char *ChooseIndexName(const char *tabname, Oid namespaceId,
+ 				List *colnames, List *exclusionOpNames,
+ 				bool primary, bool isconstraint);
  static char *ChooseIndexNameAddition(List *colnames);
+ static List *ChooseIndexColumnNames(List *indexElems);
  static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
  								Oid relId, Oid oldRelId, void *arg);
  
*************** CheckIndexCompatible(Oid oldId,
*** 268,327 ****
   * DefineIndex
   *		Creates a new index.
   *
!  * 'heapRelation': the relation the index will apply to.
!  * 'indexRelationName': the name for the new index, or NULL to indicate
!  *		that a nonconflicting default name should be picked.
   * 'indexRelationId': normally InvalidOid, but during bootstrap can be
   *		nonzero to specify a preselected OID for the index.
-  * 'relFileNode': normally InvalidOid, but can be nonzero to specify existing
-  *		storage constituting a valid build of this index.
-  * 'accessMethodName': name of the AM to use.
-  * 'tableSpaceName': name of the tablespace to create the index in.
-  *		NULL specifies using the appropriate default.
-  * 'attributeList': a list of IndexElem specifying columns and expressions
-  *		to index on.
-  * 'predicate': the partial-index condition, or NULL if none.
-  * 'options': reloptions from WITH (in list-of-DefElem form).
-  * 'exclusionOpNames': list of names of exclusion-constraint operators,
-  *		or NIL if not an exclusion constraint.
-  * 'unique': make the index enforce uniqueness.
-  * 'primary': mark the index as a primary key in the catalogs.
-  * 'isconstraint': index is for a PRIMARY KEY or UNIQUE constraint,
-  *		so build a pg_constraint entry for it.
-  * 'deferrable': constraint is DEFERRABLE.
-  * 'initdeferred': constraint is INITIALLY DEFERRED.
   * 'is_alter_table': this is due to an ALTER rather than a CREATE operation.
   * 'check_rights': check for CREATE rights in the namespace.  (This should
   *		be true except when ALTER is deleting/recreating an index.)
   * 'skip_build': make the catalog entries but leave the index file empty;
   *		it will be filled later.
   * 'quiet': suppress the NOTICE chatter ordinarily provided for constraints.
-  * 'concurrent': avoid blocking writers to the table while building.
   *
   * Returns the OID of the created index.
   */
  Oid
! DefineIndex(RangeVar *heapRelation,
! 			char *indexRelationName,
  			Oid indexRelationId,
- 			Oid relFileNode,
- 			char *accessMethodName,
- 			char *tableSpaceName,
- 			List *attributeList,
- 			Expr *predicate,
- 			List *options,
- 			List *exclusionOpNames,
- 			bool unique,
- 			bool primary,
- 			bool isconstraint,
- 			bool deferrable,
- 			bool initdeferred,
  			bool is_alter_table,
  			bool check_rights,
  			bool skip_build,
! 			bool quiet,
! 			bool concurrent)
  {
  	Oid		   *typeObjectId;
  	Oid		   *collationObjectId;
  	Oid		   *classObjectId;
--- 273,300 ----
   * DefineIndex
   *		Creates a new index.
   *
!  * 'stmt': IndexStmt describing the properties of the new index.
   * 'indexRelationId': normally InvalidOid, but during bootstrap can be
   *		nonzero to specify a preselected OID for the index.
   * 'is_alter_table': this is due to an ALTER rather than a CREATE operation.
   * 'check_rights': check for CREATE rights in the namespace.  (This should
   *		be true except when ALTER is deleting/recreating an index.)
   * 'skip_build': make the catalog entries but leave the index file empty;
   *		it will be filled later.
   * 'quiet': suppress the NOTICE chatter ordinarily provided for constraints.
   *
   * Returns the OID of the created index.
   */
  Oid
! DefineIndex(IndexStmt *stmt,
  			Oid indexRelationId,
  			bool is_alter_table,
  			bool check_rights,
  			bool skip_build,
! 			bool quiet)
  {
+ 	char	   *indexRelationName;
+ 	char	   *accessMethodName;
  	Oid		   *typeObjectId;
  	Oid		   *collationObjectId;
  	Oid		   *classObjectId;
*************** DefineIndex(RangeVar *heapRelation,
*** 354,360 ****
  	/*
  	 * count attributes in index
  	 */
! 	numberOfAttributes = list_length(attributeList);
  	if (numberOfAttributes <= 0)
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
--- 327,333 ----
  	/*
  	 * count attributes in index
  	 */
! 	numberOfAttributes = list_length(stmt->indexParams);
  	if (numberOfAttributes <= 0)
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
*************** DefineIndex(RangeVar *heapRelation,
*** 372,379 ****
  	 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
  	 * (but not VACUUM).
  	 */
! 	rel = heap_openrv(heapRelation,
! 					  (concurrent ? ShareUpdateExclusiveLock : ShareLock));
  
  	relationId = RelationGetRelid(rel);
  	namespaceId = RelationGetNamespace(rel);
--- 345,352 ----
  	 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
  	 * (but not VACUUM).
  	 */
! 	rel = heap_openrv(stmt->relation,
! 					  (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));
  
  	relationId = RelationGetRelid(rel);
  	namespaceId = RelationGetNamespace(rel);
*************** DefineIndex(RangeVar *heapRelation,
*** 389,400 ****
  			ereport(ERROR,
  					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  					 errmsg("cannot create index on foreign table \"%s\"",
! 							heapRelation->relname)));
  		else
  			ereport(ERROR,
  					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  					 errmsg("\"%s\" is not a table",
! 							heapRelation->relname)));
  	}
  
  	/*
--- 362,373 ----
  			ereport(ERROR,
  					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  					 errmsg("cannot create index on foreign table \"%s\"",
! 							stmt->relation->relname)));
  		else
  			ereport(ERROR,
  					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  					 errmsg("\"%s\" is not a table",
! 							stmt->relation->relname)));
  	}
  
  	/*
*************** DefineIndex(RangeVar *heapRelation,
*** 426,434 ****
  	 * Select tablespace to use.  If not specified, use default tablespace
  	 * (which may in turn default to database's default).
  	 */
! 	if (tableSpaceName)
  	{
! 		tablespaceId = get_tablespace_oid(tableSpaceName, false);
  	}
  	else
  	{
--- 399,407 ----
  	 * Select tablespace to use.  If not specified, use default tablespace
  	 * (which may in turn default to database's default).
  	 */
! 	if (stmt->tableSpace)
  	{
! 		tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
  	}
  	else
  	{
*************** DefineIndex(RangeVar *heapRelation,
*** 463,484 ****
  	/*
  	 * Choose the index column names.
  	 */
! 	indexColNames = ChooseIndexColumnNames(attributeList);
  
  	/*
  	 * Select name for index if caller didn't specify
  	 */
  	if (indexRelationName == NULL)
  		indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
  											namespaceId,
  											indexColNames,
! 											exclusionOpNames,
! 											primary,
! 											isconstraint);
  
  	/*
  	 * look up the access method, verify it can handle the requested features
  	 */
  	tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
  	if (!HeapTupleIsValid(tuple))
  	{
--- 436,459 ----
  	/*
  	 * Choose the index column names.
  	 */
! 	indexColNames = ChooseIndexColumnNames(stmt->indexParams);
  
  	/*
  	 * Select name for index if caller didn't specify
  	 */
+ 	indexRelationName = stmt->idxname;
  	if (indexRelationName == NULL)
  		indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
  											namespaceId,
  											indexColNames,
! 											stmt->excludeOpNames,
! 											stmt->primary,
! 											stmt->isconstraint);
  
  	/*
  	 * look up the access method, verify it can handle the requested features
  	 */
+ 	accessMethodName = stmt->accessMethod;
  	tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
  	if (!HeapTupleIsValid(tuple))
  	{
*************** DefineIndex(RangeVar *heapRelation,
*** 503,509 ****
  	accessMethodId = HeapTupleGetOid(tuple);
  	accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
  
! 	if (unique && !accessMethodForm->amcanunique)
  		ereport(ERROR,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  			   errmsg("access method \"%s\" does not support unique indexes",
--- 478,484 ----
  	accessMethodId = HeapTupleGetOid(tuple);
  	accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
  
! 	if (stmt->unique && !accessMethodForm->amcanunique)
  		ereport(ERROR,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  			   errmsg("access method \"%s\" does not support unique indexes",
*************** DefineIndex(RangeVar *heapRelation,
*** 513,519 ****
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  		  errmsg("access method \"%s\" does not support multicolumn indexes",
  				 accessMethodName)));
! 	if (exclusionOpNames != NIL && !OidIsValid(accessMethodForm->amgettuple))
  		ereport(ERROR,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  		errmsg("access method \"%s\" does not support exclusion constraints",
--- 488,494 ----
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  		  errmsg("access method \"%s\" does not support multicolumn indexes",
  				 accessMethodName)));
! 	if (stmt->excludeOpNames && !OidIsValid(accessMethodForm->amgettuple))
  		ereport(ERROR,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  		errmsg("access method \"%s\" does not support exclusion constraints",
*************** DefineIndex(RangeVar *heapRelation,
*** 527,539 ****
  	/*
  	 * Validate predicate, if given
  	 */
! 	if (predicate)
! 		CheckPredicate(predicate);
  
  	/*
  	 * Parse AM-specific options, convert to text array form, validate.
  	 */
! 	reloptions = transformRelOptions((Datum) 0, options, NULL, NULL, false, false);
  
  	(void) index_reloptions(amoptions, reloptions, true);
  
--- 502,515 ----
  	/*
  	 * Validate predicate, if given
  	 */
! 	if (stmt->whereClause)
! 		CheckPredicate((Expr *) stmt->whereClause);
  
  	/*
  	 * Parse AM-specific options, convert to text array form, validate.
  	 */
! 	reloptions = transformRelOptions((Datum) 0, stmt->options,
! 									 NULL, NULL, false, false);
  
  	(void) index_reloptions(amoptions, reloptions, true);
  
*************** DefineIndex(RangeVar *heapRelation,
*** 545,559 ****
  	indexInfo->ii_NumIndexAttrs = numberOfAttributes;
  	indexInfo->ii_Expressions = NIL;	/* for now */
  	indexInfo->ii_ExpressionsState = NIL;
! 	indexInfo->ii_Predicate = make_ands_implicit(predicate);
  	indexInfo->ii_PredicateState = NIL;
  	indexInfo->ii_ExclusionOps = NULL;
  	indexInfo->ii_ExclusionProcs = NULL;
  	indexInfo->ii_ExclusionStrats = NULL;
! 	indexInfo->ii_Unique = unique;
  	/* In a concurrent build, mark it not-ready-for-inserts */
! 	indexInfo->ii_ReadyForInserts = !concurrent;
! 	indexInfo->ii_Concurrent = concurrent;
  	indexInfo->ii_BrokenHotChain = false;
  
  	typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
--- 521,535 ----
  	indexInfo->ii_NumIndexAttrs = numberOfAttributes;
  	indexInfo->ii_Expressions = NIL;	/* for now */
  	indexInfo->ii_ExpressionsState = NIL;
! 	indexInfo->ii_Predicate = make_ands_implicit((Expr *) stmt->whereClause);
  	indexInfo->ii_PredicateState = NIL;
  	indexInfo->ii_ExclusionOps = NULL;
  	indexInfo->ii_ExclusionProcs = NULL;
  	indexInfo->ii_ExclusionStrats = NULL;
! 	indexInfo->ii_Unique = stmt->unique;
  	/* In a concurrent build, mark it not-ready-for-inserts */
! 	indexInfo->ii_ReadyForInserts = !stmt->concurrent;
! 	indexInfo->ii_Concurrent = stmt->concurrent;
  	indexInfo->ii_BrokenHotChain = false;
  
  	typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
*************** DefineIndex(RangeVar *heapRelation,
*** 562,591 ****
  	coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
  	ComputeIndexAttrs(indexInfo,
  					  typeObjectId, collationObjectId, classObjectId,
! 					  coloptions, attributeList,
! 					  exclusionOpNames, relationId,
  					  accessMethodName, accessMethodId,
! 					  amcanorder, isconstraint);
  
  	/*
  	 * Extra checks when creating a PRIMARY KEY index.
  	 */
! 	if (primary)
  		index_check_primary_key(rel, indexInfo, is_alter_table);
  
  	/*
  	 * Report index creation if appropriate (delay this till after most of the
  	 * error checks)
  	 */
! 	if (isconstraint && !quiet)
  	{
  		const char *constraint_type;
  
! 		if (primary)
  			constraint_type = "PRIMARY KEY";
! 		else if (unique)
  			constraint_type = "UNIQUE";
! 		else if (exclusionOpNames != NIL)
  			constraint_type = "EXCLUDE";
  		else
  		{
--- 538,567 ----
  	coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
  	ComputeIndexAttrs(indexInfo,
  					  typeObjectId, collationObjectId, classObjectId,
! 					  coloptions, stmt->indexParams,
! 					  stmt->excludeOpNames, relationId,
  					  accessMethodName, accessMethodId,
! 					  amcanorder, stmt->isconstraint);
  
  	/*
  	 * Extra checks when creating a PRIMARY KEY index.
  	 */
! 	if (stmt->primary)
  		index_check_primary_key(rel, indexInfo, is_alter_table);
  
  	/*
  	 * Report index creation if appropriate (delay this till after most of the
  	 * error checks)
  	 */
! 	if (stmt->isconstraint && !quiet)
  	{
  		const char *constraint_type;
  
! 		if (stmt->primary)
  			constraint_type = "PRIMARY KEY";
! 		else if (stmt->unique)
  			constraint_type = "UNIQUE";
! 		else if (stmt->excludeOpNames != NIL)
  			constraint_type = "EXCLUDE";
  		else
  		{
*************** DefineIndex(RangeVar *heapRelation,
*** 601,627 ****
  	}
  
  	/*
! 	 * A valid relFileNode implies that we already have a built form of the
  	 * index.  The caller should also decline any index build.
  	 */
! 	Assert(!OidIsValid(relFileNode) || (skip_build && !concurrent));
  
  	/*
  	 * Make the catalog entries for the index, including constraints. Then, if
  	 * not skip_build || concurrent, actually build the index.
  	 */
  	indexRelationId =
! 		index_create(rel, indexRelationName, indexRelationId, relFileNode,
  					 indexInfo, indexColNames,
  					 accessMethodId, tablespaceId,
  					 collationObjectId, classObjectId,
! 					 coloptions, reloptions, primary,
! 					 isconstraint, deferrable, initdeferred,
  					 allowSystemTableMods,
! 					 skip_build || concurrent,
! 					 concurrent);
  
! 	if (!concurrent)
  	{
  		/* Close the heap and we're done, in the non-concurrent case */
  		heap_close(rel, NoLock);
--- 577,607 ----
  	}
  
  	/*
! 	 * A valid stmt->oldNode implies that we already have a built form of the
  	 * index.  The caller should also decline any index build.
  	 */
! 	Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent));
  
  	/*
  	 * Make the catalog entries for the index, including constraints. Then, if
  	 * not skip_build || concurrent, actually build the index.
  	 */
  	indexRelationId =
! 		index_create(rel, indexRelationName, indexRelationId, stmt->oldNode,
  					 indexInfo, indexColNames,
  					 accessMethodId, tablespaceId,
  					 collationObjectId, classObjectId,
! 					 coloptions, reloptions, stmt->primary,
! 					 stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
  					 allowSystemTableMods,
! 					 skip_build || stmt->concurrent,
! 					 stmt->concurrent);
  
! 	if (stmt->idxcomment != NULL)
! 		CreateComments(indexRelationId, RelationRelationId, 0,
! 					   stmt->idxcomment);
! 
! 	if (!stmt->concurrent)
  	{
  		/* Close the heap and we're done, in the non-concurrent case */
  		heap_close(rel, NoLock);
*************** DefineIndex(RangeVar *heapRelation,
*** 709,715 ****
  	 */
  
  	/* Open and lock the parent heap relation */
! 	rel = heap_openrv(heapRelation, ShareUpdateExclusiveLock);
  
  	/* And the target index relation */
  	indexRelation = index_open(indexRelationId, RowExclusiveLock);
--- 689,695 ----
  	 */
  
  	/* Open and lock the parent heap relation */
! 	rel = heap_openrv(stmt->relation, ShareUpdateExclusiveLock);
  
  	/* And the target index relation */
  	indexRelation = index_open(indexRelationId, RowExclusiveLock);
*************** DefineIndex(RangeVar *heapRelation,
*** 724,730 ****
  	indexInfo->ii_BrokenHotChain = false;
  
  	/* Now build the index */
! 	index_build(rel, indexRelation, indexInfo, primary, false);
  
  	/* Close both the relations, but keep the locks */
  	heap_close(rel, NoLock);
--- 704,710 ----
  	indexInfo->ii_BrokenHotChain = false;
  
  	/* Now build the index */
! 	index_build(rel, indexRelation, indexInfo, stmt->primary, false);
  
  	/* Close both the relations, but keep the locks */
  	heap_close(rel, NoLock);
*************** ChooseRelationName(const char *name1, co
*** 1594,1600 ****
   *
   * The argument list is pretty ad-hoc :-(
   */
! char *
  ChooseIndexName(const char *tabname, Oid namespaceId,
  				List *colnames, List *exclusionOpNames,
  				bool primary, bool isconstraint)
--- 1574,1580 ----
   *
   * The argument list is pretty ad-hoc :-(
   */
! static char *
  ChooseIndexName(const char *tabname, Oid namespaceId,
  				List *colnames, List *exclusionOpNames,
  				bool primary, bool isconstraint)
*************** ChooseIndexNameAddition(List *colnames)
*** 1676,1682 ****
   *
   * Returns a List of plain strings (char *, not String nodes).
   */
! List *
  ChooseIndexColumnNames(List *indexElems)
  {
  	List	   *result = NIL;
--- 1656,1662 ----
   *
   * Returns a List of plain strings (char *, not String nodes).
   */
! static List *
  ChooseIndexColumnNames(List *indexElems)
  {
  	List	   *result = NIL;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d69809a2f866de511e7ce278b8dca9bf9db33d40..70e408cb6ea1fc6a80b943f22d3a91d226226bb8 100644
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecAddIndex(AlteredTableInfo *tab, Re
*** 5389,5394 ****
--- 5389,5395 ----
  	Oid			new_index;
  
  	Assert(IsA(stmt, IndexStmt));
+ 	Assert(!stmt->concurrent);
  
  	/* suppress schema rights check when rebuilding existing index */
  	check_rights = !is_rebuild;
*************** ATExecAddIndex(AlteredTableInfo *tab, Re
*** 5399,5424 ****
  
  	/* The IndexStmt has already been through transformIndexStmt */
  
! 	new_index = DefineIndex(stmt->relation,		/* relation */
! 							stmt->idxname,		/* index name */
  							InvalidOid, /* no predefined OID */
- 							stmt->oldNode,
- 							stmt->accessMethod, /* am name */
- 							stmt->tableSpace,
- 							stmt->indexParams,	/* parameters */
- 							(Expr *) stmt->whereClause,
- 							stmt->options,
- 							stmt->excludeOpNames,
- 							stmt->unique,
- 							stmt->primary,
- 							stmt->isconstraint,
- 							stmt->deferrable,
- 							stmt->initdeferred,
  							true,		/* is_alter_table */
  							check_rights,
  							skip_build,
! 							quiet,
! 							false);
  
  	/*
  	 * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
--- 5400,5411 ----
  
  	/* The IndexStmt has already been through transformIndexStmt */
  
! 	new_index = DefineIndex(stmt,
  							InvalidOid, /* no predefined OID */
  							true,		/* is_alter_table */
  							check_rights,
  							skip_build,
! 							quiet);
  
  	/*
  	 * If TryReuseIndex() stashed a relfilenode for us, we used it for the new
*************** ATPostAlterTypeParse(Oid oldId, char *cm
*** 7968,7974 ****
  static void
  TryReuseIndex(Oid oldId, IndexStmt *stmt)
  {
- 
  	if (CheckIndexCompatible(oldId,
  							 stmt->relation,
  							 stmt->accessMethod,
--- 7955,7960 ----
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1743b8fdc89735f0f619c290e7286be23f3e72e6..9bac99452d334b6e7a92c662b1287d552945c6d9 100644
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
*************** _copyIndexStmt(const IndexStmt *from)
*** 2826,2831 ****
--- 2826,2832 ----
  	COPY_NODE_FIELD(options);
  	COPY_NODE_FIELD(whereClause);
  	COPY_NODE_FIELD(excludeOpNames);
+ 	COPY_STRING_FIELD(idxcomment);
  	COPY_SCALAR_FIELD(indexOid);
  	COPY_SCALAR_FIELD(oldNode);
  	COPY_SCALAR_FIELD(unique);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index f19ad7702618dcfb7f3be416dc535e6ac11b1b5e..2171d8d018bab95e0ed118384ddf8416502a86e8 100644
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
*************** _equalIndexStmt(const IndexStmt *a, cons
*** 1250,1255 ****
--- 1250,1256 ----
  	COMPARE_NODE_FIELD(options);
  	COMPARE_NODE_FIELD(whereClause);
  	COMPARE_NODE_FIELD(excludeOpNames);
+ 	COMPARE_STRING_FIELD(idxcomment);
  	COMPARE_SCALAR_FIELD(indexOid);
  	COMPARE_SCALAR_FIELD(oldNode);
  	COMPARE_SCALAR_FIELD(unique);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index d6dff9de47a982d6e41ea191af2f0415be181d7f..91b54265afe6dadb4f171ec9abdf5ff7ec9c69c5 100644
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
*************** _outIndexStmt(StringInfo str, const Inde
*** 1994,1999 ****
--- 1994,2000 ----
  	WRITE_NODE_FIELD(options);
  	WRITE_NODE_FIELD(whereClause);
  	WRITE_NODE_FIELD(excludeOpNames);
+ 	WRITE_STRING_FIELD(idxcomment);
  	WRITE_OID_FIELD(indexOid);
  	WRITE_OID_FIELD(oldNode);
  	WRITE_BOOL_FIELD(unique);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7e6ceedc42af9362a6dbdb49c6373dcf02eecfb6..1a17337a7ec6a80353e6391964e12c0242a55854 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** IndexStmt:	CREATE opt_unique INDEX opt_c
*** 5837,5843 ****
--- 5837,5850 ----
  					n->options = $12;
  					n->tableSpace = $13;
  					n->whereClause = $14;
+ 					n->excludeOpNames = NIL;
+ 					n->idxcomment = NULL;
  					n->indexOid = InvalidOid;
+ 					n->oldNode = InvalidOid;
+ 					n->primary = false;
+ 					n->isconstraint = false;
+ 					n->deferrable = false;
+ 					n->initdeferred = false;
  					$$ = (Node *)n;
  				}
  		;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index e01e103774ea2c6b1d429eb12e716b5da54bc4f9..c22c6ed21f76e0846da1d2886e4371501878af2f 100644
*** a/src/backend/parser/parse_utilcmd.c
--- b/src/backend/parser/parse_utilcmd.c
*************** static void transformTableLikeClause(Cre
*** 106,112 ****
  						 TableLikeClause *table_like_clause);
  static void transformOfType(CreateStmtContext *cxt,
  				TypeName *ofTypename);
- static char *chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt);
  static IndexStmt *generateClonedIndexStmt(CreateStmtContext *cxt,
  						Relation source_idx,
  						const AttrNumber *attmap, int attmap_length);
--- 106,111 ----
*************** transformTableLikeClause(CreateStmtConte
*** 872,904 ****
  			index_stmt = generateClonedIndexStmt(cxt, parent_index,
  												 attmap, tupleDesc->natts);
  
! 			/* Copy comment on index */
  			if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
  			{
  				comment = GetComment(parent_index_oid, RelationRelationId, 0);
  
! 				if (comment != NULL)
! 				{
! 					CommentStmt *stmt;
! 
! 					/*
! 					 * We have to assign the index a name now, so that we can
! 					 * reference it in CommentStmt.
! 					 */
! 					if (index_stmt->idxname == NULL)
! 						index_stmt->idxname = chooseIndexName(cxt->relation,
! 															  index_stmt);
! 
! 					stmt = makeNode(CommentStmt);
! 					stmt->objtype = OBJECT_INDEX;
! 					stmt->objname =
! 						list_make2(makeString(cxt->relation->schemaname),
! 								   makeString(index_stmt->idxname));
! 					stmt->objargs = NIL;
! 					stmt->comment = comment;
! 
! 					cxt->alist = lappend(cxt->alist, stmt);
! 				}
  			}
  
  			/* Save it in the inh_indexes list for the time being */
--- 871,886 ----
  			index_stmt = generateClonedIndexStmt(cxt, parent_index,
  												 attmap, tupleDesc->natts);
  
! 			/* Copy comment on index, if requested */
  			if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
  			{
  				comment = GetComment(parent_index_oid, RelationRelationId, 0);
  
! 				/*
! 				 * We make use of IndexStmt's idxcomment option, so as not to
! 				 * need to know now what name the index will have.
! 				 */
! 				index_stmt->idxcomment = comment;
  			}
  
  			/* Save it in the inh_indexes list for the time being */
*************** transformOfType(CreateStmtContext *cxt, 
*** 961,989 ****
  }
  
  /*
-  * chooseIndexName
-  *
-  * Compute name for an index.  This must match code in indexcmds.c.
-  *
-  * XXX this is inherently broken because the indexes aren't created
-  * immediately, so we fail to resolve conflicts when the same name is
-  * derived for multiple indexes.  However, that's a reasonably uncommon
-  * situation, so we'll live with it for now.
-  */
- static char *
- chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
- {
- 	Oid			namespaceId;
- 	List	   *colnames;
- 
- 	namespaceId = RangeVarGetCreationNamespace(relation);
- 	colnames = ChooseIndexColumnNames(index_stmt->indexParams);
- 	return ChooseIndexName(relation->relname, namespaceId,
- 						   colnames, index_stmt->excludeOpNames,
- 						   index_stmt->primary, index_stmt->isconstraint);
- }
- 
- /*
   * Generate an IndexStmt node using information from an already existing index
   * "source_idx".  Attribute numbers should be adjusted according to attmap.
   */
--- 943,948 ----
*************** generateClonedIndexStmt(CreateStmtContex
*** 1046,1052 ****
--- 1005,1014 ----
  		index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
  	else
  		index->tableSpace = NULL;
+ 	index->excludeOpNames = NIL;
+ 	index->idxcomment = NULL;
  	index->indexOid = InvalidOid;
+ 	index->oldNode = InvalidOid;
  	index->unique = idxrec->indisunique;
  	index->primary = idxrec->indisprimary;
  	index->concurrent = false;
*************** transformIndexConstraint(Constraint *con
*** 1504,1510 ****
--- 1466,1474 ----
  	index->whereClause = constraint->where_clause;
  	index->indexParams = NIL;
  	index->excludeOpNames = NIL;
+ 	index->idxcomment = NULL;
  	index->indexOid = InvalidOid;
+ 	index->oldNode = InvalidOid;
  	index->concurrent = false;
  
  	/*
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 33b292e6b7a9c1e47fb34de126cbc34dc5246693..7f36a09f46d297d4e98782c842a0a0f9d7ccb8e7 100644
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
*************** standard_ProcessUtility(Node *parsetree,
*** 921,946 ****
  				stmt = transformIndexStmt(stmt, queryString);
  
  				/* ... and do it */
! 				DefineIndex(stmt->relation,		/* relation */
! 							stmt->idxname,		/* index name */
  							InvalidOid, /* no predefined OID */
- 							InvalidOid, /* no previous storage */
- 							stmt->accessMethod, /* am name */
- 							stmt->tableSpace,
- 							stmt->indexParams,	/* parameters */
- 							(Expr *) stmt->whereClause,
- 							stmt->options,
- 							stmt->excludeOpNames,
- 							stmt->unique,
- 							stmt->primary,
- 							stmt->isconstraint,
- 							stmt->deferrable,
- 							stmt->initdeferred,
  							false,		/* is_alter_table */
  							true,		/* check_rights */
  							false,		/* skip_build */
! 							false,		/* quiet */
! 							stmt->concurrent);	/* concurrent */
  			}
  			break;
  
--- 921,932 ----
  				stmt = transformIndexStmt(stmt, queryString);
  
  				/* ... and do it */
! 				DefineIndex(stmt,
  							InvalidOid, /* no predefined OID */
  							false,		/* is_alter_table */
  							true,		/* check_rights */
  							false,		/* skip_build */
! 							false);		/* quiet */
  			}
  			break;
  
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 8f3d2c358dceb73587a934284fb6340b91d91cb4..9b6d57a21e23c38688874bef9fe4a423c6d49289 100644
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 20,45 ****
  extern void RemoveObjects(DropStmt *stmt);
  
  /* commands/indexcmds.c */
! extern Oid DefineIndex(RangeVar *heapRelation,
! 			char *indexRelationName,
  			Oid indexRelationId,
- 			Oid relFileNode,
- 			char *accessMethodName,
- 			char *tableSpaceName,
- 			List *attributeList,
- 			Expr *predicate,
- 			List *options,
- 			List *exclusionOpNames,
- 			bool unique,
- 			bool primary,
- 			bool isconstraint,
- 			bool deferrable,
- 			bool initdeferred,
  			bool is_alter_table,
  			bool check_rights,
  			bool skip_build,
! 			bool quiet,
! 			bool concurrent);
  extern void ReindexIndex(RangeVar *indexRelation);
  extern void ReindexTable(RangeVar *relation);
  extern void ReindexDatabase(const char *databaseName,
--- 20,31 ----
  extern void RemoveObjects(DropStmt *stmt);
  
  /* commands/indexcmds.c */
! extern Oid DefineIndex(IndexStmt *stmt,
  			Oid indexRelationId,
  			bool is_alter_table,
  			bool check_rights,
  			bool skip_build,
! 			bool quiet);
  extern void ReindexIndex(RangeVar *indexRelation);
  extern void ReindexTable(RangeVar *relation);
  extern void ReindexDatabase(const char *databaseName,
*************** extern char *makeObjectName(const char *
*** 48,57 ****
  			   const char *label);
  extern char *ChooseRelationName(const char *name1, const char *name2,
  				   const char *label, Oid namespaceid);
- extern char *ChooseIndexName(const char *tabname, Oid namespaceId,
- 				List *colnames, List *exclusionOpNames,
- 				bool primary, bool isconstraint);
- extern List *ChooseIndexColumnNames(List *indexElems);
  extern bool CheckIndexCompatible(Oid oldId,
  					 RangeVar *heapRelation,
  					 char *accessMethodName,
--- 34,39 ----
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 50111cba3c0eca1f5abe341bbee6bb0464b0439f..a4591cc9aa4060ebbc569d014f0404eadbe8af56 100644
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef struct FetchStmt
*** 2018,2027 ****
   *		Create Index Statement
   *
   * This represents creation of an index and/or an associated constraint.
!  * If indexOid isn't InvalidOid, we are not creating an index, just a
!  * UNIQUE/PKEY constraint using an existing index.	isconstraint must always
!  * be true in this case, and the fields describing the index properties are
!  * empty.
   * ----------------------
   */
  typedef struct IndexStmt
--- 2018,2028 ----
   *		Create Index Statement
   *
   * This represents creation of an index and/or an associated constraint.
!  * If isconstraint is true, we should create a pg_constraint entry along
!  * with the index.  But if indexOid isn't InvalidOid, we are not creating an
!  * index, just a UNIQUE/PKEY constraint using an existing index.  isconstraint
!  * must always be true in this case, and the fields describing the index
!  * properties are empty.
   * ----------------------
   */
  typedef struct IndexStmt
*************** typedef struct IndexStmt
*** 2031,2045 ****
  	RangeVar   *relation;		/* relation to build index on */
  	char	   *accessMethod;	/* name of access method (eg. btree) */
  	char	   *tableSpace;		/* tablespace, or NULL for default */
! 	List	   *indexParams;	/* a list of IndexElem */
! 	List	   *options;		/* options from WITH clause */
  	Node	   *whereClause;	/* qualification (partial-index predicate) */
  	List	   *excludeOpNames; /* exclusion operator names, or NIL if none */
  	Oid			indexOid;		/* OID of an existing index, if any */
! 	Oid			oldNode;		/* relfilenode of my former self */
  	bool		unique;			/* is index unique? */
! 	bool		primary;		/* is index on primary key? */
! 	bool		isconstraint;	/* is it from a CONSTRAINT clause? */
  	bool		deferrable;		/* is the constraint DEFERRABLE? */
  	bool		initdeferred;	/* is the constraint INITIALLY DEFERRED? */
  	bool		concurrent;		/* should this be a concurrent index build? */
--- 2032,2047 ----
  	RangeVar   *relation;		/* relation to build index on */
  	char	   *accessMethod;	/* name of access method (eg. btree) */
  	char	   *tableSpace;		/* tablespace, or NULL for default */
! 	List	   *indexParams;	/* columns to index: a list of IndexElem */
! 	List	   *options;		/* WITH clause options: a list of DefElem */
  	Node	   *whereClause;	/* qualification (partial-index predicate) */
  	List	   *excludeOpNames; /* exclusion operator names, or NIL if none */
+ 	char	   *idxcomment;		/* comment to apply to index, or NULL */
  	Oid			indexOid;		/* OID of an existing index, if any */
! 	Oid			oldNode;		/* relfilenode of existing storage, if any */
  	bool		unique;			/* is index unique? */
! 	bool		primary;		/* is index a primary key? */
! 	bool		isconstraint;	/* is it for a pkey/unique constraint? */
  	bool		deferrable;		/* is the constraint DEFERRABLE? */
  	bool		initdeferred;	/* is the constraint INITIALLY DEFERRED? */
  	bool		concurrent;		/* should this be a concurrent index build? */