Index: src/backend/access/gist/gistvacuum.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/gist/gistvacuum.c,v
retrieving revision 1.11
diff -c -r1.11 gistvacuum.c
*** src/backend/access/gist/gistvacuum.c	22 Nov 2005 18:17:05 -0000	1.11
--- src/backend/access/gist/gistvacuum.c	7 Dec 2005 11:52:43 -0000
***************
*** 125,131 ****
  					if (chldtuple.ituplen > 1)
  					{
  						/*
! 						 * child was splitted, so we need mark completion
  						 * insert(split)
  						 */
  						int			j;
--- 125,131 ----
  					if (chldtuple.ituplen > 1)
  					{
  						/*
! 						 * child was split, so we need mark completion
  						 * insert(split)
  						 */
  						int			j;
***************
*** 329,337 ****
  }
  
  /*
!  * For usial vacuum just update FSM, for full vacuum
   * reforms parent tuples if some of childs was deleted or changed,
!  * update invalid tuples (they can exsist from last crash recovery only),
   * tries to get smaller index
   */
  
--- 329,337 ----
  }
  
  /*
!  * For usual vacuum just update FSM, for full vacuum
   * reforms parent tuples if some of childs was deleted or changed,
!  * update invalid tuples (they can exist from last crash recovery only),
   * tries to get smaller index
   */
  
***************
*** 505,514 ****
  			   *ptr;
  	bool		needLock;
  
! 	stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
! 
! 	stack->blkno = GIST_ROOT_BLKNO;
! 	needFullVacuum = false;
  
  	while (stack)
  	{
--- 505,519 ----
  			   *ptr;
  	bool		needLock;
  
!     if (callback_state)
!     {
!     	stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
! 
! 	   stack->blkno = GIST_ROOT_BLKNO;
! 	   needFullVacuum = false;
!     }
!     else
!         stack = NULL;
  
  	while (stack)
  	{
Index: src/backend/access/hash/hash.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/hash/hash.c,v
retrieving revision 1.82
diff -c -r1.82 hash.c
*** src/backend/access/hash/hash.c	6 Nov 2005 19:29:00 -0000	1.82
--- src/backend/access/hash/hash.c	7 Dec 2005 11:52:43 -0000
***************
*** 504,509 ****
--- 504,520 ----
  	tuples_removed = 0;
  	num_index_tuples = 0;
  
+ 	/* return statistics */
+ 	num_pages = RelationGetNumberOfBlocks(rel);
+ 
+ 	result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
+ 	result->num_pages = num_pages;
+ 
+     if (!callback_state)
+     {
+         	PG_RETURN_POINTER(result);
+     }
+ 
  	/*
  	 * Read the metapage to fetch original bucket and tuple counts.  Also, we
  	 * keep a copy of the last-seen metapage so that we can use its
***************
*** 652,662 ****
  
  	_hash_wrtbuf(rel, metabuf);
  
- 	/* return statistics */
- 	num_pages = RelationGetNumberOfBlocks(rel);
- 
- 	result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
- 	result->num_pages = num_pages;
  	result->num_index_tuples = num_index_tuples;
  	result->tuples_removed = tuples_removed;
  
--- 663,668 ----
Index: src/backend/access/index/indexam.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/index/indexam.c,v
retrieving revision 1.87
diff -c -r1.87 indexam.c
*** src/backend/access/index/indexam.c	3 Dec 2005 05:51:00 -0000	1.87
--- src/backend/access/index/indexam.c	7 Dec 2005 11:52:44 -0000
***************
*** 685,690 ****
--- 685,695 ----
   *		callback routine tells whether a given main-heap tuple is
   *		to be deleted
   *
+  *      passing NULL callback_state can be interpreted by the 
+  *      index access method as meaning that the index does not need
+  *      to be scanned in logical sequence to remove rows for this call
+  *      index_vacuum_cleanup is always required after this, however.
+  * 
   *		return value is an optional palloc'd struct of statistics
   * ----------------
   */
Index: src/backend/access/nbtree/nbtree.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v
retrieving revision 1.134
diff -c -r1.134 nbtree.c
*** src/backend/access/nbtree/nbtree.c	22 Nov 2005 18:17:06 -0000	1.134
--- src/backend/access/nbtree/nbtree.c	7 Dec 2005 11:52:45 -0000
***************
*** 587,592 ****
--- 587,593 ----
  	int			ndeletable;
  	Buffer		buf;
  	BlockNumber num_pages;
+     bool        scanindex = true;
  
  	tuples_removed = 0;
  	num_index_tuples = 0;
***************
*** 607,614 ****
  	 * skip obtaining exclusive lock on empty pages though, since no indexscan
  	 * could be stopped on those.
  	 */
! 	buf = _bt_get_endpoint(rel, 0, false);
! 	if (BufferIsValid(buf))		/* check for empty index */
  	{
  		for (;;)
  		{
--- 608,622 ----
  	 * skip obtaining exclusive lock on empty pages though, since no indexscan
  	 * could be stopped on those.
  	 */
!     if (callback_state)
!     {
!     	buf = _bt_get_endpoint(rel, 0, false);
!         scanindex = BufferIsValid(buf); /* check for empty index */
!     }
!     else
!         scanindex = false;
! 
! 	if (scanindex)	
  	{
  		for (;;)
  		{
***************
*** 691,697 ****
  
  	result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
  	result->num_pages = num_pages;
! 	result->num_index_tuples = num_index_tuples;
  	result->tuples_removed = tuples_removed;
  
  	PG_RETURN_POINTER(result);
--- 699,708 ----
  
  	result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
  	result->num_pages = num_pages;
!     if (scanindex)
!     	result->num_index_tuples = num_index_tuples;
!     else
!         result->num_index_tuples = -1;
  	result->tuples_removed = tuples_removed;
  
  	PG_RETURN_POINTER(result);
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.319
diff -c -r1.319 vacuum.c
*** src/backend/commands/vacuum.c	22 Nov 2005 18:17:09 -0000	1.319
--- src/backend/commands/vacuum.c	7 Dec 2005 11:52:48 -0000
***************
*** 709,715 ****
  	/* overwrite the existing statistics in the tuple */
  	pgcform = (Form_pg_class) GETSTRUCT(&rtup);
  	pgcform->relpages = (int32) num_pages;
! 	pgcform->reltuples = (float4) num_tuples;
  	pgcform->relhasindex = hasindex;
  
  	/*
--- 709,716 ----
  	/* overwrite the existing statistics in the tuple */
  	pgcform = (Form_pg_class) GETSTRUCT(&rtup);
  	pgcform->relpages = (int32) num_pages;
!     if (num_tuples >= 0 )
!     	pgcform->reltuples = (float4) num_tuples;
  	pgcform->relhasindex = hasindex;
  
  	/*
***************
*** 2951,2965 ****
  	if (!stats)
  		return;
  
! 	/* now update statistics in pg_class */
  	vac_update_relstats(RelationGetRelid(indrel),
! 						stats->num_pages, stats->num_index_tuples,
  						false);
  
  	ereport(elevel,
  			(errmsg("index \"%s\" now contains %.0f row versions in %u pages",
  					RelationGetRelationName(indrel),
! 					stats->num_index_tuples,
  					stats->num_pages),
  	errdetail("%u index pages have been deleted, %u are currently reusable.\n"
  			  "%s.",
--- 2952,2969 ----
  	if (!stats)
  		return;
  
! 	/* now update statistics in pg_class 
!      * we use the number of tuples from the table because we have not
!      * actually scanned the index, so don't know the number of tuples in index
!      */
  	vac_update_relstats(RelationGetRelid(indrel),
! 						stats->num_pages, num_tuples,
  						false);
  
  	ereport(elevel,
  			(errmsg("index \"%s\" now contains %.0f row versions in %u pages",
  					RelationGetRelationName(indrel),
! 					num_tuples,
  					stats->num_pages),
  	errdetail("%u index pages have been deleted, %u are currently reusable.\n"
  			  "%s.",
Index: src/backend/commands/vacuumlazy.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v
retrieving revision 1.63
diff -c -r1.63 vacuumlazy.c
*** src/backend/commands/vacuumlazy.c	22 Nov 2005 18:17:09 -0000	1.63
--- src/backend/commands/vacuumlazy.c	7 Dec 2005 11:52:50 -0000
***************
*** 639,654 ****
  	if (!stats)
  		return;
  
! 	/* now update statistics in pg_class */
  	vac_update_relstats(RelationGetRelid(indrel),
  						stats->num_pages,
! 						stats->num_index_tuples,
  						false);
  
  	ereport(elevel,
  			(errmsg("index \"%s\" now contains %.0f row versions in %u pages",
  					RelationGetRelationName(indrel),
! 					stats->num_index_tuples,
  					stats->num_pages),
  	errdetail("%u index pages have been deleted, %u are currently reusable.\n"
  			  "%s.",
--- 639,657 ----
  	if (!stats)
  		return;
  
! 	/* now update statistics in pg_class
!      * we use the number of tuples from the table because we have not
!      * actually scanned the index, so don't know the number of tuples in index
!      */
  	vac_update_relstats(RelationGetRelid(indrel),
  						stats->num_pages,
! 						vacrelstats->rel_tuples, 
  						false);
  
  	ereport(elevel,
  			(errmsg("index \"%s\" now contains %.0f row versions in %u pages",
  					RelationGetRelationName(indrel),
! 					vacrelstats->rel_tuples,
  					stats->num_pages),
  	errdetail("%u index pages have been deleted, %u are currently reusable.\n"
  			  "%s.",
Index: src/include/access/genam.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/access/genam.h,v
retrieving revision 1.54
diff -c -r1.54 genam.h
*** src/include/access/genam.h	3 Dec 2005 05:51:03 -0000	1.54
--- src/include/access/genam.h	7 Dec 2005 11:52:51 -0000
***************
*** 38,43 ****
--- 38,45 ----
  	BlockNumber num_pages;		/* pages remaining in index */
  	BlockNumber pages_removed;	/* # removed by bulk-delete operation */
  	double		num_index_tuples;		/* tuples remaining */
+                                 /* should set to -1 if index not scanned */
+                                 /*   because no records to delete        */
  	double		tuples_removed; /* # removed by bulk-delete operation */
  	BlockNumber pages_deleted;	/* # unused pages in index */
  	BlockNumber pages_free;		/* # pages available for reuse */
