Index: src/backend/commands/analyze.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/analyze.c,v
retrieving revision 1.35
diff -c -r1.35 analyze.c
*** src/backend/commands/analyze.c	24 May 2002 18:57:55 -0000	1.35
--- src/backend/commands/analyze.c	12 Jun 2002 03:59:45 -0000
***************
*** 156,170 ****
  		elevel = DEBUG1;
  
  	/*
- 	 * Begin a transaction for analyzing this relation.
- 	 *
- 	 * Note: All memory allocated during ANALYZE will live in
- 	 * TransactionCommandContext or a subcontext thereof, so it will all
- 	 * be released by transaction commit at the end of this routine.
- 	 */
- 	StartTransactionCommand();
- 
- 	/*
  	 * Check for user-requested abort.	Note we want this to be inside a
  	 * transaction, so xact.c doesn't issue useless WARNING.
  	 */
--- 156,161 ----
***************
*** 177,186 ****
  	if (!SearchSysCacheExists(RELOID,
  							  ObjectIdGetDatum(relid),
  							  0, 0, 0))
- 	{
- 		CommitTransactionCommand();
  		return;
- 	}
  
  	/*
  	 * Open the class, getting only a read lock on it, and check
--- 168,174 ----
***************
*** 196,202 ****
  			elog(WARNING, "Skipping \"%s\" --- only table or database owner can ANALYZE it",
  				 RelationGetRelationName(onerel));
  		relation_close(onerel, AccessShareLock);
- 		CommitTransactionCommand();
  		return;
  	}
  
--- 184,189 ----
***************
*** 211,217 ****
  			elog(WARNING, "Skipping \"%s\" --- can not process indexes, views or special system tables",
  				 RelationGetRelationName(onerel));
  		relation_close(onerel, AccessShareLock);
- 		CommitTransactionCommand();
  		return;
  	}
  
--- 198,203 ----
***************
*** 222,228 ****
  		strcmp(RelationGetRelationName(onerel), StatisticRelationName) == 0)
  	{
  		relation_close(onerel, AccessShareLock);
- 		CommitTransactionCommand();
  		return;
  	}
  
--- 208,213 ----
***************
*** 283,289 ****
  	if (attr_cnt <= 0)
  	{
  		relation_close(onerel, NoLock);
- 		CommitTransactionCommand();
  		return;
  	}
  
--- 268,273 ----
***************
*** 370,378 ****
  	 * entries we made in pg_statistic.)
  	 */
  	relation_close(onerel, NoLock);
- 
- 	/* Commit and release working memory */
- 	CommitTransactionCommand();
  }
  
  /*
--- 354,359 ----
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.226
diff -c -r1.226 vacuum.c
*** src/backend/commands/vacuum.c	24 May 2002 18:57:56 -0000	1.226
--- src/backend/commands/vacuum.c	12 Jun 2002 03:59:54 -0000
***************
*** 110,117 ****
  
  
  /* non-export function prototypes */
- static void vacuum_init(VacuumStmt *vacstmt);
- static void vacuum_shutdown(VacuumStmt *vacstmt);
  static List *getrels(const RangeVar *vacrel, const char *stmttype);
  static void vac_update_dbstats(Oid dbid,
  				   TransactionId vacuumXID,
--- 110,115 ----
***************
*** 160,165 ****
--- 158,165 ----
  void
  vacuum(VacuumStmt *vacstmt)
  {
+ 	MemoryContext anl_context,
+ 				  old_context;
  	const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
  	List	   *vrl,
  			   *cur;
***************
*** 178,190 ****
  	 * user's transaction too, which would certainly not be the desired
  	 * behavior.
  	 */
! 	if (IsTransactionBlock())
  		elog(ERROR, "%s cannot run inside a BEGIN/END block", stmttype);
  
  	/* Running VACUUM from a function would free the function context */
! 	if (!MemoryContextContains(QueryContext, vacstmt))
  		elog(ERROR, "%s cannot be executed from a function", stmttype);
!                         
  	/*
  	 * Send info about dead objects to the statistics collector
  	 */
--- 178,190 ----
  	 * user's transaction too, which would certainly not be the desired
  	 * behavior.
  	 */
! 	if (vacstmt->vacuum && IsTransactionBlock())
  		elog(ERROR, "%s cannot run inside a BEGIN/END block", stmttype);
  
  	/* Running VACUUM from a function would free the function context */
! 	if (vacstmt->vacuum && !MemoryContextContains(QueryContext, vacstmt))
  		elog(ERROR, "%s cannot be executed from a function", stmttype);
! 
  	/*
  	 * Send info about dead objects to the statistics collector
  	 */
***************
*** 203,215 ****
  										ALLOCSET_DEFAULT_INITSIZE,
  										ALLOCSET_DEFAULT_MAXSIZE);
  
  	/* Build list of relations to process (note this lives in vac_context) */
  	vrl = getrels(vacstmt->relation, stmttype);
  
  	/*
! 	 * Start up the vacuum cleaner.
  	 */
! 	vacuum_init(vacstmt);
  
  	/*
  	 * Process each selected relation.	We are careful to process each
--- 203,264 ----
  										ALLOCSET_DEFAULT_INITSIZE,
  										ALLOCSET_DEFAULT_MAXSIZE);
  
+ 	if (vacstmt->analyze && !vacstmt->vacuum)
+ 		anl_context = AllocSetContextCreate(QueryContext,
+ 											"Analyze",
+ 											ALLOCSET_DEFAULT_MINSIZE,
+ 											ALLOCSET_DEFAULT_INITSIZE,
+ 											ALLOCSET_DEFAULT_MAXSIZE);
+ 
  	/* Build list of relations to process (note this lives in vac_context) */
  	vrl = getrels(vacstmt->relation, stmttype);
  
  	/*
! 	 *		Formerly, there was code here to prevent more than one VACUUM from
! 	 *		executing concurrently in the same database.  However, there's no
! 	 *		good reason to prevent that, and manually removing lockfiles after
! 	 *		a vacuum crash was a pain for dbadmins.  So, forget about lockfiles,
! 	 *		and just rely on the locks we grab on each target table
! 	 *		to ensure that there aren't two VACUUMs running on the same table
! 	 *		at the same time.
! 	 *
! 	 *		The strangeness with committing and starting transactions in the
! 	 *		init and shutdown routines is due to the fact that the vacuum cleaner
! 	 *		is invoked via an SQL command, and so is already executing inside
! 	 *		a transaction.	We need to leave ourselves in a predictable state
! 	 *		on entry and exit to the vacuum cleaner.  We commit the transaction
! 	 *		started in PostgresMain() inside vacuum_init(), and start one in
! 	 *		vacuum_shutdown() to match the commit waiting for us back in
! 	 *		PostgresMain().
  	 */
! 	if (vacstmt->vacuum)
! 	{
! 		if (vacstmt->relation == NULL)
! 		{
! 			/*
! 			 * Compute the initially applicable OldestXmin and FreezeLimit
! 			 * XIDs, so that we can record these values at the end of the
! 			 * VACUUM. Note that individual tables may well be processed with
! 			 * newer values, but we can guarantee that no (non-shared)
! 			 * relations are processed with older ones.
! 			 *
! 			 * It is okay to record non-shared values in pg_database, even though
! 			 * we may vacuum shared relations with older cutoffs, because only
! 			 * the minimum of the values present in pg_database matters.  We
! 			 * can be sure that shared relations have at some time been
! 			 * vacuumed with cutoffs no worse than the global minimum; for, if
! 			 * there is a backend in some other DB with xmin = OLDXMIN that's
! 			 * determining the cutoff with which we vacuum shared relations,
! 			 * it is not possible for that database to have a cutoff newer
! 			 * than OLDXMIN recorded in pg_database.
! 			 */
! 			vacuum_set_xid_limits(vacstmt, false,
! 								  &initialOldestXmin, &initialFreezeLimit);
! 		}
! 
! 		/* matches the StartTransaction in PostgresMain() */
! 		CommitTransactionCommand();
! 	}
  
  	/*
  	 * Process each selected relation.	We are careful to process each
***************
*** 225,305 ****
  		if (vacstmt->vacuum)
  			vacuum_rel(relid, vacstmt, RELKIND_RELATION);
  		if (vacstmt->analyze)
  			analyze_rel(relid, vacstmt);
  	}
  
  	/* clean up */
! 	vacuum_shutdown(vacstmt);
! }
! 
! /*
!  *	vacuum_init(), vacuum_shutdown() -- start up and shut down the vacuum cleaner.
!  *
!  *		Formerly, there was code here to prevent more than one VACUUM from
!  *		executing concurrently in the same database.  However, there's no
!  *		good reason to prevent that, and manually removing lockfiles after
!  *		a vacuum crash was a pain for dbadmins.  So, forget about lockfiles,
!  *		and just rely on the locks we grab on each target table
!  *		to ensure that there aren't two VACUUMs running on the same table
!  *		at the same time.
!  *
!  *		The strangeness with committing and starting transactions in the
!  *		init and shutdown routines is due to the fact that the vacuum cleaner
!  *		is invoked via an SQL command, and so is already executing inside
!  *		a transaction.	We need to leave ourselves in a predictable state
!  *		on entry and exit to the vacuum cleaner.  We commit the transaction
!  *		started in PostgresMain() inside vacuum_init(), and start one in
!  *		vacuum_shutdown() to match the commit waiting for us back in
!  *		PostgresMain().
!  */
! static void
! vacuum_init(VacuumStmt *vacstmt)
! {
! 	if (vacstmt->vacuum && vacstmt->relation == NULL)
  	{
! 		/*
! 		 * Compute the initially applicable OldestXmin and FreezeLimit
! 		 * XIDs, so that we can record these values at the end of the
! 		 * VACUUM. Note that individual tables may well be processed with
! 		 * newer values, but we can guarantee that no (non-shared)
! 		 * relations are processed with older ones.
! 		 *
! 		 * It is okay to record non-shared values in pg_database, even though
! 		 * we may vacuum shared relations with older cutoffs, because only
! 		 * the minimum of the values present in pg_database matters.  We
! 		 * can be sure that shared relations have at some time been
! 		 * vacuumed with cutoffs no worse than the global minimum; for, if
! 		 * there is a backend in some other DB with xmin = OLDXMIN that's
! 		 * determining the cutoff with which we vacuum shared relations,
! 		 * it is not possible for that database to have a cutoff newer
! 		 * than OLDXMIN recorded in pg_database.
! 		 */
! 		vacuum_set_xid_limits(vacstmt, false,
! 							  &initialOldestXmin, &initialFreezeLimit);
! 	}
! 
! 	/* matches the StartTransaction in PostgresMain() */
! 	CommitTransactionCommand();
! }
  
! static void
! vacuum_shutdown(VacuumStmt *vacstmt)
! {
! 	/* on entry, we are not in a transaction */
! 
! 	/* matches the CommitTransaction in PostgresMain() */
! 	StartTransactionCommand();
  
! 	/*
! 	 * If we did a database-wide VACUUM, update the database's pg_database
! 	 * row with info about the transaction IDs used, and try to truncate
! 	 * pg_clog.
! 	 */
! 	if (vacstmt->vacuum && vacstmt->relation == NULL)
! 	{
! 		vac_update_dbstats(MyDatabaseId,
! 						   initialOldestXmin, initialFreezeLimit);
! 		vac_truncate_clog(initialOldestXmin, initialFreezeLimit);
  	}
  
  	/*
--- 274,317 ----
  		if (vacstmt->vacuum)
  			vacuum_rel(relid, vacstmt, RELKIND_RELATION);
  		if (vacstmt->analyze)
+ 		{
+ 			/* If we vacuumed, use new transaction for analyze. */
+ 			if (vacstmt->vacuum)
+ 				StartTransactionCommand();
+ 			else
+ 				old_context = MemoryContextSwitchTo(anl_context);
+ 
  			analyze_rel(relid, vacstmt);
+ 
+ 			if (vacstmt->vacuum)
+ 				CommitTransactionCommand();
+ 			else
+ 			{
+ 				MemoryContextResetAndDeleteChildren(anl_context);
+ 				MemoryContextSwitchTo(old_context);
+ 			}
+ 		}
  	}
  
  	/* clean up */
! 	if (vacstmt->vacuum)
  	{
! 		/* on entry, we are not in a transaction */
  
! 		/* matches the CommitTransaction in PostgresMain() */
! 		StartTransactionCommand();
  
! 		/*
! 		 * If we did a database-wide VACUUM, update the database's pg_database
! 		 * row with info about the transaction IDs used, and try to truncate
! 		 * pg_clog.
! 		 */
! 		if (vacstmt->relation == NULL)
! 		{
! 			vac_update_dbstats(MyDatabaseId,
! 							   initialOldestXmin, initialFreezeLimit);
! 			vac_truncate_clog(initialOldestXmin, initialFreezeLimit);
! 		}
  	}
  
  	/*
***************
*** 309,314 ****
--- 321,330 ----
  	 */
  	MemoryContextDelete(vac_context);
  	vac_context = NULL;
+ 
+ 	if (vacstmt->analyze && !vacstmt->vacuum)
+ 		MemoryContextDelete(anl_context);
+ 
  }
  
  /*
