diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 4779f3eb5b3b9fbcfe1eb7dda943abcac5202e02..94f0dd2f070cd6e44f9893793e8fba7757e499b1 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.29 1997/04/17 01:45:36 vadim Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.30 1997/04/23 06:25:43 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,6 +42,7 @@
 #include <utils/mcxt.h>
 #include <utils/inval.h>
 #include <utils/syscache.h>
+#include <utils/builtins.h>
 #include <commands/vacuum.h>
 #include <parser/catalog_utils.h>
 #include <storage/bufpage.h>
@@ -56,38 +57,41 @@
 #include <port-protos.h>
 
 bool VacuumRunning =	false;
+
+static Portal vc_portal;
+
 static int MESSAGE_LEVEL;	/* message level */
 
 #define swapLong(a,b)	{long tmp; tmp=a; a=b; b=tmp;}
 #define swapInt(a,b)	{int tmp; tmp=a; a=b; b=tmp;}
 #define swapDatum(a,b)	{Datum tmp; tmp=a; a=b; b=tmp;}
-#define VacAttrStatsEqValid(stats) ( RegProcedureIsValid(stats->cmpeq))
-#define VacAttrStatsLtGtValid(stats) ( RegProcedureIsValid(stats->cmplt) && \
-				   RegProcedureIsValid(stats->cmpgt) && \
+#define VacAttrStatsEqValid(stats) ( stats->f_cmpeq != NULL )
+#define VacAttrStatsLtGtValid(stats) ( stats->f_cmplt != NULL && \
+				   stats->f_cmpgt != NULL && \
 				   RegProcedureIsValid(stats->outfunc) )
   
 
 /* non-export function prototypes */
 static void vc_init(void);
 static void vc_shutdown(void);
-static void vc_vacuum(NameData *VacRelP);
-static VRelList vc_getrels(Portal p, NameData *VacRelP);
-static void vc_vacone (Oid relid);
+static void vc_vacuum(NameData *VacRelP, bool analyze, List *va_cols);
+static VRelList vc_getrels(NameData *VacRelP);
+static void vc_vacone (Oid relid, bool analyze, List *va_cols);
 static void vc_scanheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl);
 static void vc_rpfheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel);
 static void vc_vacheap (VRelStats *vacrelstats, Relation onerel, VPageList vpl);
 static void vc_vacpage (Page page, VPageDescr vpd, Relation archrel);
 static void vc_vaconeind (VPageList vpl, Relation indrel, int nhtups);
 static void vc_scanoneind (Relation indrel, int nhtups);
-static void vc_attrstats(Relation onerel, VacAttrStats *vacattrstats, HeapTuple htup);
+static void vc_attrstats(Relation onerel, VRelStats *vacrelstats, HeapTuple htup);
 static void vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum *bucket, int16 *bucket_len);
-static void vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VacAttrStats *vacattrstats);
-static void vc_delhilowstats(Oid relid);
+static void vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats *vacrelstats);
+static void vc_delhilowstats (Oid relid, int attcnt, int *attnums);
 static void vc_setpagelock(Relation rel, BlockNumber blkno);
 static VPageDescr vc_tidreapped (ItemPointer itemptr, VPageList vpl);
 static void vc_reappage (VPageList vpl, VPageDescr vpc);
 static void vc_vpinsert (VPageList vpl, VPageDescr vpnew);
-static void vc_free(Portal p, VRelList vrl);
+static void vc_free(VRelList vrl);
 static void vc_getindices (Oid relid, int *nindices, Relation **Irel);
 static void vc_clsindices (int nindices, Relation *Irel);
 static Relation vc_getarchrel(Relation heaprel);
@@ -100,9 +104,25 @@ static int vc_cmp_offno (char *left, char *right);
 static bool vc_enough_space (VPageDescr vpd, Size len);
 
 void
-vacuum(char *vacrel, bool verbose)
+vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec)
 {
+    char *pname;
+    MemoryContext old;
+    PortalVariableMemory pmem;
     NameData VacRel;
+    List *le;
+    List *va_cols = NIL;
+
+    /*
+     *  Create a portal for safe memory across transctions.  We need to
+     *  palloc the name space for it because our hash function expects
+     *	the name to be on a longword boundary.  CreatePortal copies the
+     *  name to safe storage for us.
+     */
+    pname = (char *) palloc(strlen(VACPNAME) + 1);
+    strcpy(pname, VACPNAME);
+    vc_portal = CreatePortal(pname);
+    pfree(pname);
 
     if (verbose)
 	MESSAGE_LEVEL = NOTICE;
@@ -112,15 +132,32 @@ vacuum(char *vacrel, bool verbose)
     /* vacrel gets de-allocated on transaction commit */
     if (vacrel)
     	strcpy(VacRel.data,vacrel);
+
+    pmem = PortalGetVariableMemory(vc_portal);
+    old = MemoryContextSwitchTo((MemoryContext)pmem);
+
+    Assert ( va_spec == NIL || analyze );
+    foreach (le, va_spec)
+    {
+    	char *col = (char*)lfirst(le);
+    	char *dest;
+    	
+    	dest = (char*) palloc (strlen (col) + 1);
+    	strcpy (dest, col);
+    	va_cols = lappend (va_cols, dest);
+    }
+    (void) MemoryContextSwitchTo(old);
     	
     /* initialize vacuum cleaner */
     vc_init();
 
     /* vacuum the database */
     if (vacrel)
-    	vc_vacuum(&VacRel);
+    	vc_vacuum (&VacRel, analyze, va_cols);
     else
-    	vc_vacuum(NULL);
+    	vc_vacuum (NULL, analyze, NIL);
+
+    PortalDestroy (&vc_portal);
 
     /* clean up */
     vc_shutdown();
@@ -199,46 +236,25 @@ vc_abort()
  *	locks at one time.
  */
 static void
-vc_vacuum(NameData *VacRelP)
+vc_vacuum(NameData *VacRelP, bool analyze, List *va_cols)
 {
     VRelList vrl, cur;
-    char *pname;
-    Portal p;
-
-    /*
-     *  Create a portal for safe memory across transctions.  We need to
-     *  palloc the name space for it because our hash function expects
-     *	the name to be on a longword boundary.  CreatePortal copies the
-     *  name to safe storage for us.
-     */
-
-    pname = (char *) palloc(strlen(VACPNAME) + 1);
-    strcpy(pname, VACPNAME);
-    p = CreatePortal(pname);
-    pfree(pname);
 
     /* get list of relations */
-    vrl = vc_getrels(p, VacRelP);
+    vrl = vc_getrels(VacRelP);
 
-    if ( vrl != NULL )
-    {
-    	if (VacRelP != NULL)
-    	    vc_delhilowstats(vrl->vrl_relid);
-    	else
-    	    vc_delhilowstats(InvalidOid);
-    }
+    if ( analyze && VacRelP == NULL && vrl != NULL )
+    	vc_delhilowstats (InvalidOid, 0, NULL);
     	
     /* vacuum each heap relation */
     for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
-	vc_vacone (cur->vrl_relid);
-
-    vc_free(p, vrl);
+	vc_vacone (cur->vrl_relid, analyze, va_cols);
 
-    PortalDestroy(&p);
+    vc_free(vrl);
 }
 
 static VRelList
-vc_getrels(Portal p, NameData *VacRelP)
+vc_getrels(NameData *VacRelP)
 {
     Relation pgclass;
     TupleDesc pgcdesc;
@@ -267,7 +283,7 @@ vc_getrels(Portal p, NameData *VacRelP)
 			       CharacterEqualRegProcedure, CharGetDatum('r'));
     }
  
-    portalmem = PortalGetVariableMemory(p);
+    portalmem = PortalGetVariableMemory(vc_portal);
     vrl = cur = (VRelList) NULL;
 
     pgclass = heap_openr(RelationRelationName);
@@ -370,7 +386,7 @@ vc_getrels(Portal p, NameData *VacRelP)
  *	us to lock the entire database during one pass of the vacuum cleaner.
  */
 static void
-vc_vacone (Oid relid)
+vc_vacone (Oid relid, bool analyze, List *va_cols)
 {
     Relation pgclass;
     TupleDesc pgcdesc;
@@ -383,8 +399,7 @@ vc_vacone (Oid relid)
     VPageListData Fvpl;	/* List of pages with space enough for re-using */
     VPageDescr *vpp;
     Relation *Irel;
-    int32 nindices, i, attr_cnt;
-    AttributeTupleForm *attr;
+    int32 nindices, i;
     VRelStats *vacrelstats;
     
     StartTransactionCommand();
@@ -412,55 +427,117 @@ vc_vacone (Oid relid)
     /* now open the class and vacuum it */
     onerel = heap_open(relid);
 
-    attr_cnt = onerel->rd_att->natts;
-    attr = onerel->rd_att->attrs;
-
     vacrelstats = (VRelStats *) palloc(sizeof(VRelStats));
     vacrelstats->relid = relid;
     vacrelstats->npages = vacrelstats->ntups = 0;
     vacrelstats->hasindex = false;
-    vacrelstats->vacattrstats =
-		(VacAttrStats *) palloc(attr_cnt * sizeof(VacAttrStats));
+    if ( analyze && !IsSystemRelationName ((RelationGetRelationName (onerel))->data) )
+    {
+    	int attr_cnt, *attnums = NULL;
+    	AttributeTupleForm *attr;
+    	
+    	attr_cnt = onerel->rd_att->natts;
+    	attr = onerel->rd_att->attrs;
+    	
+    	if ( va_cols != NIL )
+    	{
+    	    int tcnt = 0;
+    	    List *le;
+    	    
+    	    if ( length (va_cols) > attr_cnt )
+    	    	elog (WARN, "vacuum: too many attributes specified for relation %.*s",
+    	    		NAMEDATALEN, (RelationGetRelationName(onerel))->data);
+    	    attnums = (int*) palloc (attr_cnt * sizeof (int));
+    	    foreach (le, va_cols)
+    	    {
+    	    	char *col = (char*) lfirst(le);
+    	    	    
+    	    	for (i = 0; i < attr_cnt; i++)
+    	    	{
+    	    	    if ( namestrcmp (&(attr[i]->attname), col) == 0 )
+    	    	    	break;
+    	    	}
+    	    	if ( i < attr_cnt )		/* found */
+    	    	    attnums[tcnt++] = i;
+    	    	else
+    	    	{
+    	    	    elog (WARN, "vacuum: there is no attribute %s in %.*s",
+    	    	    	col, NAMEDATALEN, (RelationGetRelationName(onerel))->data);
+    	    	}
+    	    }
+    	    attr_cnt = tcnt;
+    	}
+    	    	
+    	vacrelstats->vacattrstats = 
+    		(VacAttrStats *) palloc (attr_cnt * sizeof(VacAttrStats));
     
-    for (i = 0; i < attr_cnt; i++) {
-	Operator func_operator;
-	OperatorTupleForm pgopform;
-	VacAttrStats *stats = &vacrelstats->vacattrstats[i];
-
-	stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE);
-	memmove(stats->attr,attr[i],ATTRIBUTE_TUPLE_SIZE);
-	stats->best = stats->guess1 = stats->guess2 = 0;
-	stats->max = stats->min = 0;
-	stats->best_len = stats->guess1_len = stats->guess2_len = 0;
-	stats->max_len = stats->min_len = 0;
-	stats->initialized = false;
-	stats->best_cnt = stats->guess1_cnt = stats->guess1_hits = stats->guess2_hits = 0;
-	stats->max_cnt = stats->min_cnt = stats->null_cnt = stats->nonnull_cnt = 0;
+    	for (i = 0; i < attr_cnt; i++)
+    	{
+	    Operator func_operator;
+	    OperatorTupleForm pgopform;
+	    VacAttrStats *stats;
+
+	    stats = &vacrelstats->vacattrstats[i];
+	    stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE);
+	    memmove (stats->attr, attr[((attnums) ? attnums[i] : i)], ATTRIBUTE_TUPLE_SIZE);
+	    stats->best = stats->guess1 = stats->guess2 = 0;
+	    stats->max = stats->min = 0;
+	    stats->best_len = stats->guess1_len = stats->guess2_len = 0;
+	    stats->max_len = stats->min_len = 0;
+	    stats->initialized = false;
+	    stats->best_cnt = stats->guess1_cnt = stats->guess1_hits = stats->guess2_hits = 0;
+	    stats->max_cnt = stats->min_cnt = stats->null_cnt = stats->nonnull_cnt = 0;
 	
-        func_operator = oper("=",stats->attr->atttypid,stats->attr->atttypid,true);
-	if (func_operator != NULL) {
-	    pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
-	    stats->cmpeq = pgopform->oprcode;
-	}
-	else	stats->cmpeq = InvalidOid;
-        func_operator = oper("<",stats->attr->atttypid,stats->attr->atttypid,true);
-	if (func_operator != NULL) {
-	    pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
-	    stats->cmplt = pgopform->oprcode;
-	}
-	else	stats->cmplt = InvalidOid;
-        func_operator = oper(">",stats->attr->atttypid,stats->attr->atttypid,true);
-	if (func_operator != NULL) {
-	    pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
-	    stats->cmpgt = pgopform->oprcode;
-	}
-	else	stats->cmpgt = InvalidOid;
-	pgttup = SearchSysCacheTuple(TYPOID,
+            func_operator = oper("=",stats->attr->atttypid,stats->attr->atttypid,true);
+	    if (func_operator != NULL)
+	    {
+	    	int nargs;
+	    
+	    	pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+	    	fmgr_info (pgopform->oprcode, &(stats->f_cmpeq), &nargs);
+	    }
+	    else
+	    	stats->f_cmpeq = NULL;
+	
+            func_operator = oper("<",stats->attr->atttypid,stats->attr->atttypid,true);
+	    if (func_operator != NULL)
+	    {
+	    	int nargs;
+	    
+	    	pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+	    	fmgr_info (pgopform->oprcode, &(stats->f_cmplt), &nargs);
+	    }
+	    else
+	    	stats->f_cmplt = NULL;
+	
+            func_operator = oper(">",stats->attr->atttypid,stats->attr->atttypid,true);
+	    if (func_operator != NULL)
+	    {
+	    	int nargs;
+	    
+	    	pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+	    	fmgr_info (pgopform->oprcode, &(stats->f_cmpgt), &nargs);
+	    }
+	    else
+	    	stats->f_cmpgt = NULL;
+	
+	    pgttup = SearchSysCacheTuple(TYPOID,
                                     ObjectIdGetDatum(stats->attr->atttypid),
                                     0,0,0);
-        if (HeapTupleIsValid(pgttup))
-            stats->outfunc = ((TypeTupleForm) GETSTRUCT(pgttup))->typoutput;
-	else	stats->outfunc = InvalidOid;
+            if (HeapTupleIsValid(pgttup))
+            	stats->outfunc = ((TypeTupleForm) GETSTRUCT(pgttup))->typoutput;
+	    else
+	    	stats->outfunc = InvalidOid;
+    	}
+    	vacrelstats->va_natts = attr_cnt;
+    	vc_delhilowstats (relid, ((attnums) ? attr_cnt : 0), attnums);
+    	if ( attnums )
+    	    pfree (attnums);
+    }
+    else
+    {
+    	vacrelstats->va_natts = 0;
+    	vacrelstats->vacattrstats = (VacAttrStats *) NULL;
     }
 
     /* we require the relation to be locked until the indices are cleaned */
@@ -522,7 +599,7 @@ vc_vacone (Oid relid)
 
     /* update statistics in pg_class */
     vc_updstats(vacrelstats->relid, vacrelstats->npages, vacrelstats->ntups,
-			 vacrelstats->hasindex, vacrelstats->vacattrstats);
+			 vacrelstats->hasindex, vacrelstats);
 
     /* next command frees attribute stats */
 
@@ -748,7 +825,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
 		    min_tlen = htup->t_len;
 		if ( htup->t_len > max_tlen )
 		    max_tlen = htup->t_len;
-		vc_attrstats(onerel, vacrelstats->vacattrstats, htup);
+		vc_attrstats(onerel, vacrelstats, htup);
 	    }
 	}
 
@@ -1384,8 +1461,8 @@ vc_scanoneind (Relation indrel, int nhtups)
 	ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
 
     if ( nitups != nhtups )
-    	elog (NOTICE, "NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
-    		nitups, nhtups);
+    	elog (NOTICE, "Ind %.*s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
+    		NAMEDATALEN, indrel->rd_rel->relname.data, nitups, nhtups);
 
 } /* vc_scanoneind */
 
@@ -1463,8 +1540,8 @@ vc_vaconeind(VPageList vpl, Relation indrel, int nhtups)
 	ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
 
     if ( nitups != nhtups )
-    	elog (NOTICE, "NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
-    		nitups, nhtups);
+    	elog (NOTICE, "Ind %.*s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
+    		NAMEDATALEN, indrel->rd_rel->relname.data, nitups, nhtups);
 
 } /* vc_vaconeind */
 
@@ -1532,23 +1609,20 @@ vc_tidreapped(ItemPointer itemptr, VPageList vpl)
  *
  */
 static void
-vc_attrstats(Relation onerel, VacAttrStats *vacattrstats, HeapTuple htup)
+vc_attrstats(Relation onerel, VRelStats *vacrelstats, HeapTuple htup)
 {
-    int i, attr_cnt;
-    AttributeTupleForm *attr;
-    TupleDesc tupDesc;
+    int i, attr_cnt = vacrelstats->va_natts;
+    VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
+    TupleDesc tupDesc = onerel->rd_att;
     Datum value;
     bool isnull;
 
-    attr_cnt = onerel->rd_att->natts;
-    attr = onerel->rd_att->attrs;
-    tupDesc = onerel->rd_att;
-
     for (i = 0; i < attr_cnt; i++) {
 	VacAttrStats *stats = &vacattrstats[i];
 	bool value_hit = true;
 
-	value = (Datum) heap_getattr(htup, InvalidBuffer, i+1, tupDesc, &isnull);
+	value = (Datum) heap_getattr (htup, InvalidBuffer, 
+					stats->attr->attnum, tupDesc, &isnull);
 
 	if (!VacAttrStatsEqValid(stats))
 		continue;
@@ -1571,26 +1645,26 @@ vc_attrstats(Relation onerel, VacAttrStats *vacattrstats, HeapTuple htup)
 		stats->initialized = true;
 	    }
 	    if (VacAttrStatsLtGtValid(stats)) {
-		if (fmgr(stats->cmplt,value,stats->min)) {
+		if ( (*(stats->f_cmplt)) (value,stats->min) ) {
 		    vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
 		    stats->min_cnt = 0;
 	    	}
-		if (fmgr(stats->cmpgt,value,stats->max)) {
+		if ( (*(stats->f_cmpgt)) (value,stats->max) ) {
 		    vc_bucketcpy(stats->attr, value, &stats->max, &stats->max_len);
 		    stats->max_cnt = 0;
 	    	}
-	    	if (fmgr(stats->cmpeq,value,stats->min))
+	    	if ( (*(stats->f_cmpeq)) (value,stats->min) )
 		    stats->min_cnt++;
-		else if (fmgr(stats->cmpeq,value,stats->max))
+		else if ( (*(stats->f_cmpeq)) (value,stats->max) )
 		    stats->max_cnt++;
 	    }
-	    if (fmgr(stats->cmpeq,value,stats->best))
-		stats->	best_cnt++;
-	    else if (fmgr(stats->cmpeq,value,stats->guess1)) {
+	    if ( (*(stats->f_cmpeq)) (value,stats->best) )
+		stats->best_cnt++;
+	    else if ( (*(stats->f_cmpeq)) (value,stats->guess1) ) {
 		stats->guess1_cnt++;
-		stats->	guess1_hits++;
+		stats->guess1_hits++;
 	    }
-	    else if (fmgr(stats->cmpeq,value,stats->guess2))
+	    else if ( (*(stats->f_cmpeq)) (value,stats->guess2) )
 		stats->guess2_hits++;
 	    else value_hit = false;
 
@@ -1605,12 +1679,12 @@ vc_attrstats(Relation onerel, VacAttrStats *vacattrstats, HeapTuple htup)
 		swapInt(stats->best_len,stats->guess1_len);
 		swapLong(stats->best_cnt,stats->guess1_cnt);
 		stats->guess1_hits = 1;
-		stats->	guess2_hits = 1;
+		stats->guess2_hits = 1;
 	    }
 	    if (!value_hit) {
 		vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
 		stats->guess1_hits = 1;
-		stats->	guess2_hits = 1;
+		stats->guess2_hits = 1;
 	    }
 	}
     }
@@ -1652,7 +1726,7 @@ vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum *bucket, int16 *bucket_
  *	historical queries very expensive.
  */
 static void
-vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VacAttrStats *vacattrstats)
+vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats *vacrelstats)
 {
     Relation rd, ad, sd;
     HeapScanDesc rsdesc, asdesc;
@@ -1684,8 +1758,11 @@ vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VacAttrStats *vacat
     pgcform->relpages = npages;
     pgcform->relhasindex = hasindex;
 
-    if (vacattrstats != NULL)
+    if ( vacrelstats != NULL && vacrelstats->va_natts > 0 )
     {
+    	VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
+    	int natts = vacrelstats->va_natts;
+    	
     	ad = heap_openr(AttributeRelationName);
 	sd = heap_openr(StatisticRelationName);
         ScanKeyEntryInitialize(&askey, 0, Anum_pg_attribute_attrelid,
@@ -1693,19 +1770,27 @@ vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VacAttrStats *vacat
 
 	asdesc = heap_beginscan(ad, false, NowTimeQual, 1, &askey);
 
-	while (HeapTupleIsValid(atup = heap_getnext(asdesc, 0, &abuf))) {
-	    int slot, i;
+	while (HeapTupleIsValid(atup = heap_getnext(asdesc, 0, &abuf)))
+	{
+	    int i;
 	    double selratio;  /* average ratio of rows selected for a random constant */
 	    VacAttrStats *stats;
 	    Datum values[ Natts_pg_statistic ];
     	    char nulls[ Natts_pg_statistic ];
 
 	    attp = (AttributeTupleForm) GETSTRUCT(atup);
-	    slot = attp->attnum - 1;
-	    if (slot < 0) /* skip system attributes for now,
-			   they are unique anyway */
-		continue;            
-	    stats = &vacattrstats[slot];
+	    if ( attp->attnum <= 0)	/* skip system attributes for now, */
+			   		/* they are unique anyway */
+		continue;
+	    
+	    for (i = 0; i < natts; i++)
+	    {
+	    	if ( attp->attnum == vacattrstats[i].attr->attnum )
+	    	    break;
+	    }
+	    if ( i >= natts )
+	    	continue;
+	    stats = &(vacattrstats[i]);
 
 	    /* overwrite the existing statistics in the tuple */
 	    if (VacAttrStatsEqValid(stats)) {
@@ -1794,7 +1879,6 @@ vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VacAttrStats *vacat
     /* that's all, folks */
     heap_endscan(rsdesc);
     heap_close(rd);
-
 }
 
 /*
@@ -1802,7 +1886,7 @@ vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VacAttrStats *vacat
  *
  */
 static void
-vc_delhilowstats(Oid relid)
+vc_delhilowstats(Oid relid, int attcnt, int *attnums)
 {
     Relation pgstatistic;
     HeapScanDesc pgsscan;
@@ -1820,7 +1904,21 @@ vc_delhilowstats(Oid relid)
     else
 	pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 0, NULL);
 
-    while (HeapTupleIsValid(pgstup = heap_getnext(pgsscan, 0, NULL))) {
+    while (HeapTupleIsValid(pgstup = heap_getnext(pgsscan, 0, NULL)))
+    {
+    	if ( attcnt > 0 )
+    	{
+    	    Form_pg_statistic pgs = (Form_pg_statistic) GETSTRUCT (pgstup);
+    	    int i;
+    	    
+    	    for (i = 0; i < attcnt; i++)
+    	    {
+    	    	if ( pgs->staattnum == attnums[i] + 1 )
+    	    	    break;
+    	    }
+    	    if ( i >= attcnt )
+    	    	continue;		/* don't delete it */
+    	}
 	heap_delete(pgstatistic, &pgstup->t_ctid);
     }
 
@@ -1837,7 +1935,6 @@ static void vc_setpagelock(Relation rel, BlockNumber blkno)
     RelationSetLockForWritePage(rel, &itm);
 }
 
-
 /*
  *  vc_reappage() -- save a page on the array of reapped pages.
  *
@@ -1881,13 +1978,13 @@ vc_vpinsert (VPageList vpl, VPageDescr vpnew)
 }
 
 static void
-vc_free(Portal p, VRelList vrl)
+vc_free(VRelList vrl)
 {
     VRelList p_vrl;
     MemoryContext old;
     PortalVariableMemory pmem;
 
-    pmem = PortalGetVariableMemory(p);
+    pmem = PortalGetVariableMemory(vc_portal);
     old = MemoryContextSwitchTo((MemoryContext)pmem);
 
     while (vrl != (VRelList) NULL) {
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 224bea45d7c57eba92bd7de8951afdf048700224..6ed66f6bc81da59811e6546006008e7b9a6486e9 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: vacuum.h,v 1.6 1997/02/07 16:23:57 momjian Exp $
+ * $Id: vacuum.h,v 1.7 1997/04/23 06:28:48 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -54,7 +54,8 @@ typedef struct {
     int16 best_len, guess1_len, guess2_len, max_len, min_len;
     int32 best_cnt, guess1_cnt, guess1_hits, guess2_hits, null_cnt,nonnull_cnt;
     int32 max_cnt, min_cnt;
-    regproc cmpeq, cmplt, cmpgt, outfunc;
+    func_ptr f_cmpeq, f_cmplt, f_cmpgt;
+    regproc outfunc;
     bool initialized;
 } VacAttrStats;
 
@@ -72,14 +73,14 @@ typedef struct VRelStats {
     Size		min_tlen;
     Size		max_tlen;
     bool		hasindex;
-    int			natts;
+    int			va_natts;	/* number of attrs being analyzed */
     VacAttrStats	*vacattrstats;
 } VRelStats;
 
 extern bool VacuumRunning;
 
 extern void vc_abort(void);
-extern void vacuum(char *vacrel, bool verbose);
+extern void vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec);
 
 #define ATTNVALS_SCALE 	1000000000 /* XXX so it can act as a float4 */