diff -cprN head/src/backend/commands/cluster.c work/src/backend/commands/cluster.c
*** head/src/backend/commands/cluster.c	2009-10-06 04:24:36.000000000 +0900
--- work/src/backend/commands/cluster.c	2009-10-23 11:43:39.105505012 +0900
*************** cluster(ClusterStmt *stmt, bool isTopLev
*** 122,128 ****
  					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  			   errmsg("cannot cluster temporary tables of other sessions")));
  
! 		if (stmt->indexname == NULL)
  		{
  			ListCell   *index;
  
--- 122,131 ----
  					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  			   errmsg("cannot cluster temporary tables of other sessions")));
  
! 		if (stmt->without_index)
! 		{
! 		}
! 		else if (stmt->indexname == NULL)
  		{
  			ListCell   *index;
  
*************** cluster_rel(RelToCluster *rvtc, bool rec
*** 308,347 ****
  			return;
  		}
  
! 		/*
! 		 * Check that the index still exists
! 		 */
! 		if (!SearchSysCacheExists(RELOID,
! 								  ObjectIdGetDatum(rvtc->indexOid),
! 								  0, 0, 0))
  		{
! 			relation_close(OldHeap, AccessExclusiveLock);
! 			return;
! 		}
  
! 		/*
! 		 * Check that the index is still the one with indisclustered set.
! 		 */
! 		tuple = SearchSysCache(INDEXRELID,
! 							   ObjectIdGetDatum(rvtc->indexOid),
! 							   0, 0, 0);
! 		if (!HeapTupleIsValid(tuple))	/* probably can't happen */
! 		{
! 			relation_close(OldHeap, AccessExclusiveLock);
! 			return;
! 		}
! 		indexForm = (Form_pg_index) GETSTRUCT(tuple);
! 		if (!indexForm->indisclustered)
! 		{
  			ReleaseSysCache(tuple);
- 			relation_close(OldHeap, AccessExclusiveLock);
- 			return;
  		}
- 		ReleaseSysCache(tuple);
  	}
  
  	/* Check index is valid to cluster on */
! 	check_index_is_clusterable(OldHeap, rvtc->indexOid, recheck);
  
  	/* rebuild_relation does all the dirty work */
  	ereport(verbose ? INFO : DEBUG2,
--- 311,350 ----
  			return;
  		}
  
! 		if (OidIsValid(rvtc->indexOid))
  		{
! 			/* Check that the index still exists */
! 			if (!SearchSysCacheExists(RELOID,
! 									  ObjectIdGetDatum(rvtc->indexOid),
! 									  0, 0, 0))
! 			{
! 				relation_close(OldHeap, AccessExclusiveLock);
! 				return;
! 			}
  
! 			/* Check that the index is still the one with indisclustered set. */
! 			tuple = SearchSysCache(INDEXRELID,
! 								   ObjectIdGetDatum(rvtc->indexOid),
! 								   0, 0, 0);
! 			if (!HeapTupleIsValid(tuple))	/* probably can't happen */
! 			{
! 				relation_close(OldHeap, AccessExclusiveLock);
! 				return;
! 			}
! 			indexForm = (Form_pg_index) GETSTRUCT(tuple);
! 			if (!indexForm->indisclustered)
! 			{
! 				ReleaseSysCache(tuple);
! 				relation_close(OldHeap, AccessExclusiveLock);
! 				return;
! 			}
  			ReleaseSysCache(tuple);
  		}
  	}
  
  	/* Check index is valid to cluster on */
! 	if (OidIsValid(rvtc->indexOid))
! 		check_index_is_clusterable(OldHeap, rvtc->indexOid, recheck);
  
  	/* rebuild_relation does all the dirty work */
  	ereport(verbose ? INFO : DEBUG2,
*************** rebuild_relation(Relation OldHeap, Oid i
*** 576,582 ****
  	Relation	newrel;
  
  	/* Mark the correct index as clustered */
! 	mark_index_clustered(OldHeap, indexOid);
  
  	/* Close relcache entry, but keep lock until transaction commit */
  	heap_close(OldHeap, NoLock);
--- 579,586 ----
  	Relation	newrel;
  
  	/* Mark the correct index as clustered */
! 	if (OidIsValid(indexOid))
! 		mark_index_clustered(OldHeap, indexOid);
  
  	/* Close relcache entry, but keep lock until transaction commit */
  	heap_close(OldHeap, NoLock);
*************** make_new_heap(Oid OIDOldHeap, const char
*** 753,758 ****
--- 757,834 ----
  	return OIDNewHeap;
  }
  
+ typedef struct ScanDescData
+ {
+ 	bool	isIndexScan;
+ 	void   *desc;
+ } ScanDescData;
+ 
+ typedef struct ScanDescData *ScanDesc;
+ 
+ static ScanDesc
+ genam_beginscan(Relation heapRelation,
+ 				Relation indexRelation,
+ 				Snapshot snapshot,
+ 				int nkeys, ScanKey key)
+ {
+ 	ScanDesc scan = palloc(sizeof(ScanDescData));
+ 
+ 	if (indexRelation)
+ 	{
+ 		scan->isIndexScan = true;
+ 		scan->desc = index_beginscan(heapRelation, indexRelation,
+ 									 snapshot, nkeys, key);
+ 	}
+ 	else
+ 	{
+ 		/* Do not allow syncscan not to change physical order of tuples. */
+ 		scan->isIndexScan = false;
+ 		scan->desc = heap_beginscan_strat(heapRelation,
+ 										  snapshot, nkeys, key, true, false);
+ 	}
+ 
+ 	return scan;
+ }
+ 
+ static void
+ genam_endscan(ScanDesc scan)
+ {
+ 	if (scan->isIndexScan)
+ 		index_endscan((IndexScanDesc) scan->desc);
+ 	else
+ 		heap_endscan((HeapScanDesc) scan->desc);
+ 	pfree(scan);
+ }
+ 
+ static HeapTuple
+ genam_getnext(ScanDesc scan, ScanDirection direction, Buffer *buffer)
+ {
+ 	HeapTuple	tuple;
+ 
+ 	if (scan->isIndexScan)
+ 	{
+ 		IndexScanDesc	scandesc = (IndexScanDesc) scan->desc;
+ 
+ 		tuple = index_getnext(scandesc, direction);
+ 
+ 		/* Since we used no scan keys, should never need to recheck */
+ 		if (scandesc->xs_recheck)
+ 			elog(ERROR, "CLUSTER does not support lossy index conditions");
+ 
+ 		*buffer = scandesc->xs_cbuf;
+ 	}
+ 	else
+ 	{
+ 		HeapScanDesc	scandesc = (HeapScanDesc) scan->desc;
+ 
+ 		tuple = heap_getnext(scandesc, direction);
+ 
+ 		*buffer = scandesc->rs_cbuf;
+ 	}
+ 
+ 	return tuple;
+ }
+ 
  /*
   * Do the physical copying of heap data.  Returns the TransactionId used as
   * freeze cutoff point for the tuples.
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 768,775 ****
  	int			natts;
  	Datum	   *values;
  	bool	   *isnull;
! 	IndexScanDesc scan;
  	HeapTuple	tuple;
  	bool		use_wal;
  	TransactionId OldestXmin;
  	TransactionId FreezeXid;
--- 844,852 ----
  	int			natts;
  	Datum	   *values;
  	bool	   *isnull;
! 	ScanDesc	scan;
  	HeapTuple	tuple;
+ 	Buffer		buf;
  	bool		use_wal;
  	TransactionId OldestXmin;
  	TransactionId FreezeXid;
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 780,786 ****
  	 */
  	NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
  	OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
! 	OldIndex = index_open(OIDOldIndex, AccessExclusiveLock);
  
  	/*
  	 * Their tuple descriptors should be exactly alike, but here we only need
--- 857,866 ----
  	 */
  	NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
  	OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
! 	if (OidIsValid(OIDOldIndex))
! 		OldIndex = index_open(OIDOldIndex, AccessExclusiveLock);
! 	else
! 		OldIndex = NULL;
  
  	/*
  	 * Their tuple descriptors should be exactly alike, but here we only need
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 828,837 ****
  	 * copied, we scan with SnapshotAny and use HeapTupleSatisfiesVacuum for
  	 * the visibility test.
  	 */
! 	scan = index_beginscan(OldHeap, OldIndex,
! 						   SnapshotAny, 0, (ScanKey) NULL);
  
! 	while ((tuple = index_getnext(scan, ForwardScanDirection)) != NULL)
  	{
  		HeapTuple	copiedTuple;
  		bool		isdead;
--- 908,916 ----
  	 * copied, we scan with SnapshotAny and use HeapTupleSatisfiesVacuum for
  	 * the visibility test.
  	 */
! 	scan = genam_beginscan(OldHeap, OldIndex, SnapshotAny, 0, (ScanKey) NULL);
  
! 	while ((tuple = genam_getnext(scan, ForwardScanDirection, &buf)) != NULL)
  	{
  		HeapTuple	copiedTuple;
  		bool		isdead;
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 839,852 ****
  
  		CHECK_FOR_INTERRUPTS();
  
! 		/* Since we used no scan keys, should never need to recheck */
! 		if (scan->xs_recheck)
! 			elog(ERROR, "CLUSTER does not support lossy index conditions");
  
! 		LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE);
! 
! 		switch (HeapTupleSatisfiesVacuum(tuple->t_data, OldestXmin,
! 										 scan->xs_cbuf))
  		{
  			case HEAPTUPLE_DEAD:
  				/* Definitely dead */
--- 918,926 ----
  
  		CHECK_FOR_INTERRUPTS();
  
! 		LockBuffer(buf, BUFFER_LOCK_SHARE);
  
! 		switch (HeapTupleSatisfiesVacuum(tuple->t_data, OldestXmin, buf))
  		{
  			case HEAPTUPLE_DEAD:
  				/* Definitely dead */
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 888,894 ****
  				break;
  		}
  
! 		LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
  
  		if (isdead)
  		{
--- 962,968 ----
  				break;
  		}
  
! 		LockBuffer(buf, BUFFER_LOCK_UNLOCK);
  
  		if (isdead)
  		{
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 932,938 ****
  		heap_freetuple(copiedTuple);
  	}
  
! 	index_endscan(scan);
  
  	/* Write out any remaining tuples, and fsync if needed */
  	end_heap_rewrite(rwstate);
--- 1006,1012 ----
  		heap_freetuple(copiedTuple);
  	}
  
! 	genam_endscan(scan);
  
  	/* Write out any remaining tuples, and fsync if needed */
  	end_heap_rewrite(rwstate);
*************** copy_heap_data(Oid OIDNewHeap, Oid OIDOl
*** 940,946 ****
  	pfree(values);
  	pfree(isnull);
  
! 	index_close(OldIndex, NoLock);
  	heap_close(OldHeap, NoLock);
  	heap_close(NewHeap, NoLock);
  
--- 1014,1021 ----
  	pfree(values);
  	pfree(isnull);
  
! 	if (OldIndex != NULL)
! 		index_close(OldIndex, NoLock);
  	heap_close(OldHeap, NoLock);
  	heap_close(NewHeap, NoLock);
  
diff -cprN head/src/backend/nodes/copyfuncs.c work/src/backend/nodes/copyfuncs.c
*** head/src/backend/nodes/copyfuncs.c	2009-10-15 07:14:21.000000000 +0900
--- work/src/backend/nodes/copyfuncs.c	2009-10-23 11:12:41.009498108 +0900
*************** _copyClusterStmt(ClusterStmt *from)
*** 2450,2455 ****
--- 2450,2456 ----
  	COPY_NODE_FIELD(relation);
  	COPY_STRING_FIELD(indexname);
  	COPY_SCALAR_FIELD(verbose);
+ 	COPY_SCALAR_FIELD(without_index);
  
  	return newnode;
  }
diff -cprN head/src/backend/nodes/equalfuncs.c work/src/backend/nodes/equalfuncs.c
*** head/src/backend/nodes/equalfuncs.c	2009-10-15 07:14:21.000000000 +0900
--- work/src/backend/nodes/equalfuncs.c	2009-10-23 11:12:52.845483120 +0900
*************** _equalClusterStmt(ClusterStmt *a, Cluste
*** 1073,1078 ****
--- 1073,1079 ----
  	COMPARE_NODE_FIELD(relation);
  	COMPARE_STRING_FIELD(indexname);
  	COMPARE_SCALAR_FIELD(verbose);
+ 	COMPARE_SCALAR_FIELD(without_index);
  
  	return true;
  }
diff -cprN head/src/backend/parser/gram.y work/src/backend/parser/gram.y
*** head/src/backend/parser/gram.y	2009-10-15 07:14:22.000000000 +0900
--- work/src/backend/parser/gram.y	2009-10-23 11:12:29.632497726 +0900
*************** ClusterStmt:
*** 6587,6592 ****
--- 6587,6602 ----
  				   n->relation = $3;
  				   n->indexname = $4;
  				   n->verbose = $2;
+ 				   n->without_index = false;
+ 				   $$ = (Node*)n;
+ 				}
+ 			| CLUSTER opt_verbose qualified_name WITHOUT INDEX
+ 				{
+ 			       ClusterStmt *n = makeNode(ClusterStmt);
+ 				   n->relation = $3;
+ 				   n->indexname = NULL;
+ 				   n->verbose = $2;
+ 				   n->without_index = true;
  				   $$ = (Node*)n;
  				}
  			| CLUSTER opt_verbose
*************** ClusterStmt:
*** 6595,6600 ****
--- 6605,6611 ----
  				   n->relation = NULL;
  				   n->indexname = NULL;
  				   n->verbose = $2;
+ 				   n->without_index = false;
  				   $$ = (Node*)n;
  				}
  			/* kept for pre-8.3 compatibility */
*************** ClusterStmt:
*** 6604,6609 ****
--- 6615,6621 ----
  				   n->relation = $5;
  				   n->indexname = $3;
  				   n->verbose = $2;
+ 				   n->without_index = false;
  				   $$ = (Node*)n;
  				}
  		;
diff -cprN head/src/include/nodes/parsenodes.h work/src/include/nodes/parsenodes.h
*** head/src/include/nodes/parsenodes.h	2009-10-15 07:14:24.000000000 +0900
--- work/src/include/nodes/parsenodes.h	2009-10-23 11:09:15.911477359 +0900
*************** typedef struct ClusterStmt
*** 2206,2211 ****
--- 2206,2212 ----
  	RangeVar   *relation;		/* relation being indexed, or NULL if all */
  	char	   *indexname;		/* original index defined */
  	bool		verbose;		/* print progress info */
+ 	bool		without_index;	/* no index */
  } ClusterStmt;
  
  /* ----------------------