diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index 31c560a83ad4d6a91e550b86fb8805f534fe7ee2..10bd6cb4dc16443eab32bb12fd0ac64337383f3f 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.11 2005/11/22 18:17:05 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.12 2006/02/11 16:59:08 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -125,7 +125,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
 					if (chldtuple.ituplen > 1)
 					{
 						/*
-						 * child was splitted, so we need mark completion
+						 * child was split, so we need mark completion
 						 * insert(split)
 						 */
 						int			j;
@@ -329,9 +329,9 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
 }
 
 /*
- * For usial vacuum just update FSM, for full vacuum
+ * 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 exsist from last crash recovery only),
+ * update invalid tuples (they can exist from last crash recovery only),
  * tries to get smaller index
  */
 
@@ -505,10 +505,15 @@ gistbulkdelete(PG_FUNCTION_ARGS)
 			   *ptr;
 	bool		needLock;
 
-	stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
+    if (callback_state)
+    {
+    	stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
 
-	stack->blkno = GIST_ROOT_BLKNO;
-	needFullVacuum = false;
+	   stack->blkno = GIST_ROOT_BLKNO;
+	   needFullVacuum = false;
+    }
+    else
+        stack = NULL;
 
 	while (stack)
 	{
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 3a01109125f4381033d7a6ef709d8a53571dd514..548901a9be465057e5a04a2308ecea13adc5b583 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.83 2006/01/25 23:26:11 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.84 2006/02/11 16:59:09 momjian Exp $
  *
  * NOTES
  *	  This file contains only the public interface routines.
@@ -496,6 +496,17 @@ hashbulkdelete(PG_FUNCTION_ARGS)
 	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
@@ -644,11 +655,6 @@ loop_top:
 
 	_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;
 
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index c1e61ff2bda32f883247c4e3a1f18ec6033cb23e..0365ae7942403923ccdc7860f268257633df470f 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.87 2005/12/03 05:51:00 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.88 2006/02/11 16:59:09 momjian Exp $
  *
  * INTERFACE ROUTINES
  *		index_open		- open an index relation by relation OID
@@ -685,6 +685,11 @@ index_getmulti(IndexScanDesc scan,
  *		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
  * ----------------
  */
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 45f49c0b2bd78582267549f6301f4735d699a594..e757c4adad10f20c8d89cfd21db5cee89cadf169 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.136 2006/01/25 23:04:20 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.137 2006/02/11 16:59:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -543,8 +543,9 @@ btbulkdelete(PG_FUNCTION_ARGS)
 	double		num_index_tuples;
 	OffsetNumber deletable[MaxOffsetNumber];
 	int			ndeletable;
-	Buffer		buf;
+	Buffer		buf = NULL;
 	BlockNumber num_pages;
+    bool        scanindex = true;
 
 	tuples_removed = 0;
 	num_index_tuples = 0;
@@ -565,8 +566,15 @@ btbulkdelete(PG_FUNCTION_ARGS)
 	 * 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 */
+    if (callback_state)
+    {
+    	buf = _bt_get_endpoint(rel, 0, false);
+        scanindex = BufferIsValid(buf); /* check for empty index */
+    }
+    else
+        scanindex = false;
+
+	if (scanindex)	
 	{
 		for (;;)
 		{
@@ -649,7 +657,10 @@ btbulkdelete(PG_FUNCTION_ARGS)
 
 	result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
 	result->num_pages = num_pages;
-	result->num_index_tuples = num_index_tuples;
+    if (scanindex)
+    	result->num_index_tuples = num_index_tuples;
+    else
+        result->num_index_tuples = -1;
 	result->tuples_removed = tuples_removed;
 
 	PG_RETURN_POINTER(result);
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 4a66f10bd72a813273f9e08b3ffd04fbb814f084..4e7775a6cda052764e68f46c35f914f8dfdde276 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.321 2006/01/18 20:35:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.322 2006/02/11 16:59:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -719,7 +719,8 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
 	/* overwrite the existing statistics in the tuple */
 	pgcform = (Form_pg_class) GETSTRUCT(&rtup);
 	pgcform->relpages = (int32) num_pages;
-	pgcform->reltuples = (float4) num_tuples;
+    if (num_tuples >= 0 )
+    	pgcform->reltuples = (float4) num_tuples;
 	pgcform->relhasindex = hasindex;
 
 	/*
@@ -2961,15 +2962,18 @@ scan_index(Relation indrel, double num_tuples)
 	if (!stats)
 		return;
 
-	/* now update statistics in pg_class */
+	/* 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, stats->num_index_tuples,
+						stats->num_pages, num_tuples,
 						false);
 
 	ereport(elevel,
 			(errmsg("index \"%s\" now contains %.0f row versions in %u pages",
 					RelationGetRelationName(indrel),
-					stats->num_index_tuples,
+					num_tuples,
 					stats->num_pages),
 	errdetail("%u index pages have been deleted, %u are currently reusable.\n"
 			  "%s.",
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index fbdb019b351ba7d08f5abe3657a3a47ba41080b6..0b2789da48515fdb72ed1032dfe009cb3704a520 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -31,7 +31,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.63 2005/11/22 18:17:09 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.64 2006/02/11 16:59:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -639,16 +639,19 @@ lazy_scan_index(Relation indrel, LVRelStats *vacrelstats)
 	if (!stats)
 		return;
 
-	/* now update statistics in pg_class */
+	/* 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,
-						stats->num_index_tuples,
+						vacrelstats->rel_tuples, 
 						false);
 
 	ereport(elevel,
 			(errmsg("index \"%s\" now contains %.0f row versions in %u pages",
 					RelationGetRelationName(indrel),
-					stats->num_index_tuples,
+					vacrelstats->rel_tuples,
 					stats->num_pages),
 	errdetail("%u index pages have been deleted, %u are currently reusable.\n"
 			  "%s.",
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 7dc33d3138cc766f86fb56f7e0e802df1f4b3f4a..ef9ca2146b9734b84b5cbf123fc83d32234d5d25 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.54 2005/12/03 05:51:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.55 2006/02/11 16:59:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,6 +38,8 @@ typedef struct IndexBulkDeleteResult
 	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 */