diff --git a/doc/src/sgml/mvcc.sgml b/doc/src/sgml/mvcc.sgml
index a9d7a9d5f98cf319984f1073230ead7065a5197b..d2deee2bfca50dd8a84e2989358ca87513c0f41b 100644
--- a/doc/src/sgml/mvcc.sgml
+++ b/doc/src/sgml/mvcc.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/mvcc.sgml,v 2.60 2006/09/16 00:30:14 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/mvcc.sgml,v 2.61 2006/09/17 22:50:31 tgl Exp $ -->
 
  <chapter id="mvcc">
   <title>Concurrency Control</title>
@@ -77,7 +77,7 @@
       </term>
      <listitem>
       <para>
-	A transaction reads data written by a concurrent uncommitted transaction.
+        A transaction reads data written by a concurrent uncommitted transaction.
        </para>
       </listitem>
      </varlistentry>
@@ -89,9 +89,9 @@
       </term>
      <listitem>
       <para>
-	A transaction re-reads data it has previously read and finds that data
-	has been modified by another transaction (that committed since the
-	initial read).
+        A transaction re-reads data it has previously read and finds that data
+        has been modified by another transaction (that committed since the
+        initial read).
        </para>
       </listitem>
      </varlistentry>
@@ -103,9 +103,9 @@
       </term>
      <listitem>
       <para>
-	A transaction re-executes a query returning a set of rows that satisfy a
-	search condition and finds that the set of rows satisfying the condition
-	has changed due to another recently-committed transaction.
+        A transaction re-executes a query returning a set of rows that satisfy a
+        search condition and finds that the set of rows satisfying the condition
+        has changed due to another recently-committed transaction.
        </para>
       </listitem>
      </varlistentry>
@@ -125,79 +125,79 @@
      <tgroup cols="4">
       <thead>
        <row>
-	<entry>
+        <entry>
          Isolation Level
-	</entry>
-	<entry>
-	 Dirty Read
-	</entry>
-	<entry>
-	 Nonrepeatable Read
-	</entry>
-	<entry>
-	 Phantom Read
-	</entry>
+        </entry>
+        <entry>
+         Dirty Read
+        </entry>
+        <entry>
+         Nonrepeatable Read
+        </entry>
+        <entry>
+         Phantom Read
+        </entry>
        </row>
       </thead>
       <tbody>
        <row>
-	<entry>
-	 Read uncommitted
-	</entry>
-	<entry>
-	 Possible
-	</entry>
-	<entry>
-	 Possible
-	</entry>
-	<entry>
-	 Possible
-	</entry>
+        <entry>
+         Read uncommitted
+        </entry>
+        <entry>
+         Possible
+        </entry>
+        <entry>
+         Possible
+        </entry>
+        <entry>
+         Possible
+        </entry>
        </row>
 
        <row>
-	<entry>
-	 Read committed
-	</entry>
-	<entry>
-	 Not possible
-	</entry>
-	<entry>
-	 Possible
-	</entry>
-	<entry>
-	 Possible
-	</entry>
+        <entry>
+         Read committed
+        </entry>
+        <entry>
+         Not possible
+        </entry>
+        <entry>
+         Possible
+        </entry>
+        <entry>
+         Possible
+        </entry>
        </row>
 
        <row>
-	<entry>
-	 Repeatable read
-	</entry>
-	<entry>
-	 Not possible
-	</entry>
-	<entry>
-	 Not possible
-	</entry>
-	<entry>
-	 Possible
-	</entry>
+        <entry>
+         Repeatable read
+        </entry>
+        <entry>
+         Not possible
+        </entry>
+        <entry>
+         Not possible
+        </entry>
+        <entry>
+         Possible
+        </entry>
        </row>
 
        <row>
-	<entry>
-	 Serializable
-	</entry>
-	<entry>
-	 Not possible
-	</entry>
-	<entry>
-	 Not possible
-	</entry>
-	<entry>
-	 Not possible
-	</entry>
+        <entry>
+         Serializable
+        </entry>
+        <entry>
+         Not possible
+        </entry>
+        <entry>
+         Not possible
+        </entry>
+        <entry>
+         Not possible
+        </entry>
        </row>
       </tbody>
      </tgroup>
@@ -547,174 +547,173 @@ SELECT SUM(value) FROM mytab WHERE class = 2;
       <title>Table-level lock modes</title>
       <varlistentry>
        <term>
-	<literal>ACCESS SHARE</literal>
+        <literal>ACCESS SHARE</literal>
        </term>
        <listitem>
-	<para>
-	 Conflicts with the <literal>ACCESS EXCLUSIVE</literal> lock
-	 mode only.
-	</para>
-
-	<para>
-	 The commands <command>SELECT</command> and
-	 <command>ANALYZE</command> acquire a lock of this mode on
-	 referenced tables.  In general, any query that only reads a table
-	 and does not modify it will acquire this lock mode.
-	</para>
+        <para>
+         Conflicts with the <literal>ACCESS EXCLUSIVE</literal> lock
+         mode only.
+        </para>
+
+        <para>
+         The <command>SELECT</command> command acquires a lock of this mode on
+         referenced tables.  In general, any query that only reads a table
+         and does not modify it will acquire this lock mode.
+        </para>
        </listitem>
       </varlistentry>
 
       <varlistentry>
        <term>
-	<literal>ROW SHARE</literal>
+        <literal>ROW SHARE</literal>
        </term>
        <listitem>
-	<para>
-	 Conflicts with the <literal>EXCLUSIVE</literal> and
-	 <literal>ACCESS EXCLUSIVE</literal> lock modes.
-	</para>
-
-	<para>
-	 The <command>SELECT FOR UPDATE</command> and
-	 <command>SELECT FOR SHARE</command> commands acquire a
-	 lock of this mode on the target table(s) (in addition to
-	 <literal>ACCESS SHARE</literal> locks on any other tables
-	 that are referenced but not selected
-	 <option>FOR UPDATE/FOR SHARE</option>).
-	</para>
+        <para>
+         Conflicts with the <literal>EXCLUSIVE</literal> and
+         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+        </para>
+
+        <para>
+         The <command>SELECT FOR UPDATE</command> and
+         <command>SELECT FOR SHARE</command> commands acquire a
+         lock of this mode on the target table(s) (in addition to
+         <literal>ACCESS SHARE</literal> locks on any other tables
+         that are referenced but not selected
+         <option>FOR UPDATE/FOR SHARE</option>).
+        </para>
        </listitem>
       </varlistentry>
 
       <varlistentry>
        <term>
-	<literal>ROW EXCLUSIVE</literal>
+        <literal>ROW EXCLUSIVE</literal>
        </term>
        <listitem>
-	<para>
-	 Conflicts with the <literal>SHARE</literal>, <literal>SHARE ROW
-	 EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-	 <literal>ACCESS EXCLUSIVE</literal> lock modes.
-	</para>
-
-	<para>
-	 The commands <command>UPDATE</command>,
-	 <command>DELETE</command>, and <command>INSERT</command>
-	 acquire this lock mode on the target table (in addition to
-	 <literal>ACCESS SHARE</literal> locks on any other referenced
-	 tables).  In general, this lock mode will be acquired by any
-	 command that modifies the data in a table.
-	</para>
+        <para>
+         Conflicts with the <literal>SHARE</literal>, <literal>SHARE ROW
+         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
+         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+        </para>
+
+        <para>
+         The commands <command>UPDATE</command>,
+         <command>DELETE</command>, and <command>INSERT</command>
+         acquire this lock mode on the target table (in addition to
+         <literal>ACCESS SHARE</literal> locks on any other referenced
+         tables).  In general, this lock mode will be acquired by any
+         command that modifies the data in a table.
+        </para>
        </listitem>
       </varlistentry>
 
       <varlistentry>
        <term>
-	<literal>SHARE UPDATE EXCLUSIVE</literal>
+        <literal>SHARE UPDATE EXCLUSIVE</literal>
        </term>
        <listitem>
-	<para>
-	 Conflicts with the <literal>SHARE UPDATE EXCLUSIVE</literal>,
-	 <literal>SHARE</literal>, <literal>SHARE ROW
-	 EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-	 <literal>ACCESS EXCLUSIVE</literal> lock modes.
-	 This mode protects a table against
-	 concurrent schema changes and <command>VACUUM</> runs.
-	</para>
-
-	<para>
-	 Acquired by <command>VACUUM</command> (without <option>FULL</option>)
-	 and by <command>CREATE INDEX CONCURRENTLY</>.
-	</para>
+        <para>
+         Conflicts with the <literal>SHARE UPDATE EXCLUSIVE</literal>,
+         <literal>SHARE</literal>, <literal>SHARE ROW
+         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
+         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         This mode protects a table against
+         concurrent schema changes and <command>VACUUM</> runs.
+        </para>
+
+        <para>
+         Acquired by <command>VACUUM</command> (without <option>FULL</option>),
+         <command>ANALYZE</>, and <command>CREATE INDEX CONCURRENTLY</>.
+        </para>
        </listitem>
       </varlistentry>
 
       <varlistentry>
        <term>
-	<literal>SHARE</literal>
+        <literal>SHARE</literal>
        </term>
        <listitem>
-	<para>
-	 Conflicts with the <literal>ROW EXCLUSIVE</literal>,
-	 <literal>SHARE UPDATE EXCLUSIVE</literal>, <literal>SHARE ROW
-	 EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-	 <literal>ACCESS EXCLUSIVE</literal> lock modes.
-	 This mode protects a table against concurrent data changes.
-	</para>
-
-	<para>
-	 Acquired by <command>CREATE INDEX</command>
-	 (without <option>CONCURRENTLY</option>).
-	</para>
+        <para>
+         Conflicts with the <literal>ROW EXCLUSIVE</literal>,
+         <literal>SHARE UPDATE EXCLUSIVE</literal>, <literal>SHARE ROW
+         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
+         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         This mode protects a table against concurrent data changes.
+        </para>
+
+        <para>
+         Acquired by <command>CREATE INDEX</command>
+         (without <option>CONCURRENTLY</option>).
+        </para>
        </listitem>
       </varlistentry>
 
       <varlistentry>
        <term>
-	<literal>SHARE ROW EXCLUSIVE</literal>
+        <literal>SHARE ROW EXCLUSIVE</literal>
        </term>
        <listitem>
-	<para>
-	 Conflicts with the <literal>ROW EXCLUSIVE</literal>,
-	 <literal>SHARE UPDATE EXCLUSIVE</literal>,
-	 <literal>SHARE</literal>, <literal>SHARE ROW
-	 EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-	 <literal>ACCESS EXCLUSIVE</literal> lock modes.
-	</para>
-
-	<para>
+        <para>
+         Conflicts with the <literal>ROW EXCLUSIVE</literal>,
+         <literal>SHARE UPDATE EXCLUSIVE</literal>,
+         <literal>SHARE</literal>, <literal>SHARE ROW
+         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
+         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+        </para>
+
+        <para>
          This lock mode is not automatically acquired by any
          <productname>PostgreSQL</productname> command.
-	</para>
+        </para>
        </listitem>
       </varlistentry>
 
       <varlistentry>
        <term>
-	<literal>EXCLUSIVE</literal>
+        <literal>EXCLUSIVE</literal>
        </term>
        <listitem>
-	<para>
-	 Conflicts with the <literal>ROW SHARE</literal>, <literal>ROW
-	 EXCLUSIVE</literal>, <literal>SHARE UPDATE
-	 EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE
-	 ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-	 <literal>ACCESS EXCLUSIVE</literal> lock modes.
-	 This mode allows only concurrent <literal>ACCESS SHARE</literal> locks,
-	 i.e., only reads from the table can proceed in parallel with a
-	 transaction holding this lock mode.
-	</para>
-
-	<para>
+        <para>
+         Conflicts with the <literal>ROW SHARE</literal>, <literal>ROW
+         EXCLUSIVE</literal>, <literal>SHARE UPDATE
+         EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE
+         ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
+         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         This mode allows only concurrent <literal>ACCESS SHARE</literal> locks,
+         i.e., only reads from the table can proceed in parallel with a
+         transaction holding this lock mode.
+        </para>
+
+        <para>
          This lock mode is not automatically acquired on user tables by any
          <productname>PostgreSQL</productname> command.  However it is
          acquired on certain system catalogs in some operations.
-	</para>
+        </para>
        </listitem>
       </varlistentry>
 
       <varlistentry>
        <term>
-	<literal>ACCESS EXCLUSIVE</literal>
+        <literal>ACCESS EXCLUSIVE</literal>
        </term>
        <listitem>
-	<para>
-	 Conflicts with locks of all modes (<literal>ACCESS
-	 SHARE</literal>, <literal>ROW SHARE</literal>, <literal>ROW
-	 EXCLUSIVE</literal>, <literal>SHARE UPDATE
-	 EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE
-	 ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-	 <literal>ACCESS EXCLUSIVE</literal>).
-	 This mode guarantees that the
-	 holder is the only transaction accessing the table in any way.
-	</para>
-
-	<para>
-	 Acquired by the <command>ALTER TABLE</command>, <command>DROP
-	 TABLE</command>, <command>TRUNCATE</command>, <command>REINDEX</command>,
-	 <command>CLUSTER</command>, and <command>VACUUM FULL</command>
-	 commands.  This is also the default lock mode for <command>LOCK
-	 TABLE</command> statements that do not specify a mode explicitly.
-	</para>
+        <para>
+         Conflicts with locks of all modes (<literal>ACCESS
+         SHARE</literal>, <literal>ROW SHARE</literal>, <literal>ROW
+         EXCLUSIVE</literal>, <literal>SHARE UPDATE
+         EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE
+         ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
+         <literal>ACCESS EXCLUSIVE</literal>).
+         This mode guarantees that the
+         holder is the only transaction accessing the table in any way.
+        </para>
+
+        <para>
+         Acquired by the <command>ALTER TABLE</command>, <command>DROP
+         TABLE</command>, <command>TRUNCATE</command>, <command>REINDEX</command>,
+         <command>CLUSTER</command>, and <command>VACUUM FULL</command>
+         commands.  This is also the default lock mode for <command>LOCK
+         TABLE</command> statements that do not specify a mode explicitly.
+        </para>
        </listitem>
       </varlistentry>
      </variablelist>
@@ -994,10 +993,10 @@ UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;
       </term>
       <listitem>
        <para>
-		Short-term share/exclusive page-level locks are used for 
-		read/write access. Locks are released immediately after each
-		index row is fetched or inserted. However, note that GIN index
-		usually requires several inserts per one table row.
+        Short-term share/exclusive page-level locks are used for 
+        read/write access. Locks are released immediately after each
+        index row is fetched or inserted. However, note that a GIN index
+        usually requires several inserts for each table row.
        </para>
       </listitem>
      </varlistentry>
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 2930eacb503d0841cb39f5ace4700505c5685d1a..f9e41e3531bdcfc050f5300e540f9e56d7c71ed1 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.97 2006/08/18 16:09:08 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.98 2006/09/17 22:50:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -129,10 +129,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 	CHECK_FOR_INTERRUPTS();
 
 	/*
-	 * Open the relation, getting only a read lock on it.  If the rel has
-	 * been dropped since we last saw it, we don't need to process it.
+	 * Open the relation, getting ShareUpdateExclusiveLock to ensure that
+	 * two ANALYZEs don't run on it concurrently.  (This also locks out
+	 * a concurrent VACUUM, which doesn't matter much at the moment but
+	 * might matter if we ever try to accumulate stats on dead tuples.)
+	 * If the rel has been dropped since we last saw it, we don't need
+	 * to process it.
 	 */
-	onerel = try_relation_open(relid, AccessShareLock);
+	onerel = try_relation_open(relid, ShareUpdateExclusiveLock);
 	if (!onerel)
 		return;
 
@@ -147,7 +151,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 			ereport(WARNING,
 					(errmsg("skipping \"%s\" --- only table or database owner can analyze it",
 							RelationGetRelationName(onerel))));
-		relation_close(onerel, AccessShareLock);
+		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
 	}
 
@@ -162,7 +166,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 			ereport(WARNING,
 					(errmsg("skipping \"%s\" --- cannot analyze indexes, views, or special system tables",
 							RelationGetRelationName(onerel))));
-		relation_close(onerel, AccessShareLock);
+		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
 	}
 
@@ -174,7 +178,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 	 */
 	if (isOtherTempNamespace(RelationGetNamespace(onerel)))
 	{
-		relation_close(onerel, AccessShareLock);
+		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
 	}
 
@@ -183,7 +187,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 	 */
 	if (RelationGetRelid(onerel) == StatisticRelationId)
 	{
-		relation_close(onerel, AccessShareLock);
+		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
 	}
 
@@ -317,7 +321,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 								  0, 0);
 
 		vac_close_indexes(nindexes, Irel, AccessShareLock);
-		relation_close(onerel, AccessShareLock);
+		relation_close(onerel, ShareUpdateExclusiveLock);
 		return;
 	}
 
@@ -444,7 +448,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
 	/*
 	 * Close source relation now, but keep lock so that no one deletes it
 	 * before we commit.  (If someone did, they'd fail to clean up the entries
-	 * we made in pg_statistic.)
+	 * we made in pg_statistic.  Also, releasing the lock before commit would
+	 * expose us to concurrent-update failures in update_attstats.)
 	 */
 	relation_close(onerel, NoLock);
 }
@@ -1079,14 +1084,9 @@ compare_rows(const void *a, const void *b)
  *		Note analyze_rel() has seen to it that we won't come here when
  *		vacuuming pg_statistic itself.
  *
- *		Note: if two backends concurrently try to analyze the same relation,
- *		the second one is likely to fail here with a "tuple concurrently
- *		updated" error.  This is slightly annoying, but no real harm is done.
- *		We could prevent the problem by using a stronger lock on the
- *		relation for ANALYZE (ie, ShareUpdateExclusiveLock instead
- *		of AccessShareLock); but that cure seems worse than the disease,
- *		especially now that ANALYZE doesn't start a new transaction
- *		for each relation.	The lock could be held for a long time...
+ *		Note: there would be a race condition here if two backends could
+ *		ANALYZE the same table concurrently.  Presently, we lock that out
+ *		by taking a self-exclusive lock on the relation in analyze_rel().
  */
 static void
 update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
@@ -1202,7 +1202,7 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
 		else
 		{
 			/* No, insert new tuple */
-			stup = heap_formtuple(sd->rd_att, values, nulls);
+			stup = heap_formtuple(RelationGetDescr(sd), values, nulls);
 			simple_heap_insert(sd, stup);
 		}