diff --git a/doc/src/sgml/ref/insert.sgml b/doc/src/sgml/ref/insert.sgml
index d2e29a8757759d8d1cf4a192802dbea2e866cf38..cbb0d279bd271d6d4bceaa3ea21cbeee93110411 100644
--- a/doc/src/sgml/ref/insert.sgml
+++ b/doc/src/sgml/ref/insert.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/insert.sgml,v 1.22 2003/04/26 23:56:51 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/insert.sgml,v 1.23 2003/07/03 16:32:03 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -33,7 +33,7 @@ INSERT INTO <replaceable class="PARAMETER">table</replaceable> [ ( <replaceable
   <para>
    The columns in the target list may be listed in any order.
    Each column not present in the target list will be inserted
-   using a default value, either a declared default value
+   using a default value, either its declared default value
    or null.
   </para>
 
@@ -77,7 +77,7 @@ INSERT INTO <replaceable class="PARAMETER">table</replaceable> [ ( <replaceable
     <term><literal>DEFAULT VALUES</literal></term>
     <listitem>
      <para>
-      All columns will be filled their default values.
+      All columns will be filled with their default values.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml
index 02cc07b0bd449ee832f8f0fbfb07d8c0974f8b4c..1fe85b995ed999f4322b1d0298a28df7f07723e6 100644
--- a/doc/src/sgml/ref/update.sgml
+++ b/doc/src/sgml/ref/update.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/update.sgml,v 1.22 2003/06/25 04:19:24 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/update.sgml,v 1.23 2003/07/03 16:32:12 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -28,7 +28,8 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replacea
   <para>
    <command>UPDATE</command> changes the values of the specified
    columns in all rows that satisfy the condition. Only the columns to
-   be modified need appear as columns in the statement.
+   be modified need be mentioned in the statement; columns not explicitly
+   <literal>SET</> retain their previous values.
   </para>
 
   <para>
@@ -41,8 +42,9 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replacea
   <para>
    You must have the <literal>UPDATE</literal> privilege on the table
    to update it, as well as the <literal>SELECT</literal>
-   privilege to any table whose values are read in the <replaceable
-   class="parameter">condition</replaceable>.
+   privilege to any table whose values are read in the
+   <replaceable class="parameter">expression</replaceable>s or
+   <replaceable class="parameter">condition</replaceable>.
   </para>
  </refsect1>
 
@@ -72,7 +74,8 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replacea
     <term><replaceable class="PARAMETER">expression</replaceable></term>
     <listitem>
      <para>
-      An expression or value to assign to the column.
+      An expression to assign to the column.  The expression may use the
+      old values of this and other columns in the table.
      </para>
     </listitem>
    </varlistentry>
@@ -81,7 +84,8 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replacea
     <term><literal>DEFAULT</literal></term>
     <listitem>
      <para>
-      This column will be filled with its default value.
+      Set the column to its default value (which will be NULL if no
+      specific default expression has been assigned to it).
      </para>
     </listitem>
    </varlistentry>
@@ -91,7 +95,7 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replacea
     <listitem>
      <para>
       A list of table expressions, allowing columns from other tables
-      to appear in the <literal>WHERE</> condition.
+      to appear in the <literal>WHERE</> condition and the update expressions.
      </para>
     </listitem>
    </varlistentry>
@@ -100,9 +104,9 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replacea
     <term><replaceable class="PARAMETER">condition</replaceable></term>
     <listitem>
      <para>
-      A value expression that returns a value of type
-      <type>boolean</type> that determines the rows which are to be
-      updated.
+      An expression that returns a value of type <type>boolean</type>.
+      Only rows for which this expression returns <literal>true</>
+      will be updated.
      </para>
     </listitem>
    </varlistentry>
@@ -135,9 +139,20 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replacea
    column <structfield>kind</> of the table <literal>films</literal>:
 
 <programlisting>
-UPDATE filme SET kind = 'Dramatic' WHERE kind = 'Drama';
+UPDATE films SET kind = 'Dramatic' WHERE kind = 'Drama';
 </programlisting>
   </para>
+
+  <para>
+   Adjust temperature entries and reset precipitation to its default
+   value in one row of the table <literal>weather</literal>:
+
+<programlisting>
+UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
+  WHERE city = 'San Francisco' AND date = '2003-07-03';
+</programlisting>
+  </para>
+
  </refsect1>
 
  <refsect1>
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 0caa7a55589ab8acc497aad9aa56fe56654095af..f2b896afe8f5568bf4a140ee6d285f78fed4b04d 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.258 2003/06/29 00:33:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.259 2003/07/03 16:32:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1041,6 +1041,20 @@ _copyCoerceToDomainValue(CoerceToDomainValue *from)
 	return newnode;
 }
 
+/*
+ * _copySetToDefault
+ */
+static SetToDefault *
+_copySetToDefault(SetToDefault *from)
+{
+	SetToDefault *newnode = makeNode(SetToDefault);
+
+	COPY_SCALAR_FIELD(typeId);
+	COPY_SCALAR_FIELD(typeMod);
+
+	return newnode;
+}
+
 /*
  * _copyTargetEntry
  */
@@ -1669,14 +1683,6 @@ _copyFuncWithArgs(FuncWithArgs *from)
 	return newnode;
 }
 
-static SetToDefault *
-_copySetToDefault(SetToDefault *from)
-{
-	SetToDefault *newnode = makeNode(SetToDefault);
-
-	return newnode;
-}
-
 static DeclareCursorStmt *
 _copyDeclareCursorStmt(DeclareCursorStmt *from)
 {
@@ -2607,6 +2613,9 @@ copyObject(void *from)
 		case T_CoerceToDomainValue:
 			retval = _copyCoerceToDomainValue(from);
 			break;
+		case T_SetToDefault:
+			retval = _copySetToDefault(from);
+			break;
 		case T_TargetEntry:
 			retval = _copyTargetEntry(from);
 			break;
@@ -2955,9 +2964,6 @@ copyObject(void *from)
 		case T_FuncWithArgs:
 			retval = _copyFuncWithArgs(from);
 			break;
-		case T_SetToDefault:
-			retval = _copySetToDefault(from);
-			break;
 
 		default:
 			elog(ERROR, "copyObject: don't know how to copy node type %d",
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 0f6fbaae2ee6c55f145370fb8cf206af5c6adf9c..2caca93a6b46a52d61cd3f06acac0e4dd606859e 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.201 2003/06/29 00:33:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.202 2003/07/03 16:32:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -485,6 +485,15 @@ _equalCoerceToDomainValue(CoerceToDomainValue *a, CoerceToDomainValue *b)
 	return true;
 }
 
+static bool
+_equalSetToDefault(SetToDefault *a, SetToDefault *b)
+{
+	COMPARE_SCALAR_FIELD(typeId);
+	COMPARE_SCALAR_FIELD(typeMod);
+
+	return true;
+}
+
 static bool
 _equalTargetEntry(TargetEntry *a, TargetEntry *b)
 {
@@ -740,12 +749,6 @@ _equalFuncWithArgs(FuncWithArgs *a, FuncWithArgs *b)
 	return true;
 }
 
-static bool
-_equalSetToDefault(SetToDefault *a, SetToDefault *b)
-{
-	return true;
-}
-
 static bool
 _equalDeclareCursorStmt(DeclareCursorStmt *a, DeclareCursorStmt *b)
 {
@@ -1727,6 +1730,9 @@ equal(void *a, void *b)
 		case T_CoerceToDomainValue:
 			retval = _equalCoerceToDomainValue(a, b);
 			break;
+		case T_SetToDefault:
+			retval = _equalSetToDefault(a, b);
+			break;
 		case T_TargetEntry:
 			retval = _equalTargetEntry(a, b);
 			break;
@@ -2073,9 +2079,6 @@ equal(void *a, void *b)
 		case T_FuncWithArgs:
 			retval = _equalFuncWithArgs(a, b);
 			break;
-		case T_SetToDefault:
-			retval = _equalSetToDefault(a, b);
-			break;
 
 		default:
 			elog(WARNING, "equal: don't know whether nodes of type %d are equal",
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 3b4858ee16ed99b58bc98a973e55dd08702030a3..2f622c9d7c11d322817784a7fcd34e48ffbcf10c 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.211 2003/06/29 00:33:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.212 2003/07/03 16:32:38 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -849,6 +849,15 @@ _outCoerceToDomainValue(StringInfo str, CoerceToDomainValue *node)
 	WRITE_INT_FIELD(typeMod);
 }
 
+static void
+_outSetToDefault(StringInfo str, SetToDefault *node)
+{
+	WRITE_NODE_TYPE("SETTODEFAULT");
+
+	WRITE_OID_FIELD(typeId);
+	WRITE_INT_FIELD(typeMod);
+}
+
 static void
 _outTargetEntry(StringInfo str, TargetEntry *node)
 {
@@ -1685,6 +1694,9 @@ _outNode(StringInfo str, void *obj)
 			case T_CoerceToDomainValue:
 				_outCoerceToDomainValue(str, obj);
 				break;
+			case T_SetToDefault:
+				_outSetToDefault(str, obj);
+				break;
 			case T_TargetEntry:
 				_outTargetEntry(str, obj);
 				break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index b26a7a1ae8c56385fb27a7002a5c1edb1d1e385c..da6d10c31eeaa2d6bb939a15ce0df1e5a33bb9c1 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.157 2003/06/29 00:33:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.158 2003/07/03 16:32:39 tgl Exp $
  *
  * NOTES
  *	  Path and Plan nodes do not have any readfuncs support, because we
@@ -760,6 +760,20 @@ _readCoerceToDomainValue(void)
 	READ_DONE();
 }
 
+/*
+ * _readSetToDefault
+ */
+static SetToDefault *
+_readSetToDefault(void)
+{
+	READ_LOCALS(SetToDefault);
+
+	READ_OID_FIELD(typeId);
+	READ_INT_FIELD(typeMod);
+
+	READ_DONE();
+}
+
 /*
  * _readTargetEntry
  */
@@ -1005,6 +1019,8 @@ parseNodeString(void)
 		return_value = _readCoerceToDomain();
 	else if (MATCH("COERCETODOMAINVALUE", 19))
 		return_value = _readCoerceToDomainValue();
+	else if (MATCH("SETTODEFAULT", 12))
+		return_value = _readSetToDefault();
 	else if (MATCH("TARGETENTRY", 11))
 		return_value = _readTargetEntry();
 	else if (MATCH("RANGETBLREF", 11))
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 4ed18ee5cd0e6822ad57477e7d4190537c529f7f..b3dd818e0ac3db0f5d69f60552a350881a38dd34 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.144 2003/07/01 19:07:02 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.145 2003/07/03 16:33:07 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -2157,6 +2157,7 @@ expression_tree_walker(Node *node,
 		case T_Const:
 		case T_Param:
 		case T_CoerceToDomainValue:
+		case T_SetToDefault:
 		case T_RangeTblRef:
 			/* primitive node types with no subnodes */
 			break;
@@ -2514,6 +2515,7 @@ expression_tree_mutator(Node *node,
 		case T_Const:
 		case T_Param:
 		case T_CoerceToDomainValue:
+		case T_SetToDefault:
 		case T_RangeTblRef:
 			/* primitive node types with no subnodes */
 			return (Node *) copyObject(node);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index fbd70807dff039c05a6b73d115d2984f8bb13450..d8485a2d4d7e229594a1db5f9a813cb56b3b79a4 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.424 2003/07/01 00:04:31 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.425 2003/07/03 16:33:37 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -6999,15 +6999,14 @@ update_target_el:
 					$$ = makeNode(ResTarget);
 					$$->name = $1;
 					$$->indirection = $2;
-					$$->val = (Node *)$4;
+					$$->val = (Node *) $4;
 				}
 			| ColId opt_indirection '=' DEFAULT
 				{
-					SetToDefault *def = makeNode(SetToDefault);
 					$$ = makeNode(ResTarget);
 					$$->name = $1;
-					$$->indirection = NULL;
-					$$->val = (Node *)def;
+					$$->indirection = $2;
+					$$->val = (Node *) makeNode(SetToDefault);
 				}
 
 		;
@@ -7021,11 +7020,10 @@ insert_target_el:
 			target_el								{ $$ = $1; }
 			| DEFAULT
 				{
-					SetToDefault *def = makeNode(SetToDefault);
 					$$ = makeNode(ResTarget);
 					$$->name = NULL;
-					$$->indirection = NULL;
-					$$->val = (Node *)def;
+					$$->indirection = NIL;
+					$$->val = (Node *) makeNode(SetToDefault);
 				}
 		;
 
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index b985b190bac285bca72f5289bdb40767aaa43ea1..4519c7ffb58b73044890413fe401f05e3f6912d3 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.154 2003/06/29 00:33:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.155 2003/07/03 16:34:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -914,6 +914,7 @@ transformExpr(ParseState *pstate, Node *expr)
 		case T_RelabelType:
 		case T_CoerceToDomain:
 		case T_CoerceToDomainValue:
+		case T_SetToDefault:
 			{
 				result = (Node *) expr;
 				break;
@@ -1291,6 +1292,9 @@ exprType(Node *expr)
 		case T_CoerceToDomainValue:
 			type = ((CoerceToDomainValue *) expr)->typeId;
 			break;
+		case T_SetToDefault:
+			type = ((SetToDefault *) expr)->typeId;
+			break;
 		case T_RangeVar:
 			/*
 			 * If someone uses a bare relation name in an expression,
@@ -1420,6 +1424,8 @@ exprTypmod(Node *expr)
 			return ((CoerceToDomain *) expr)->resulttypmod;
 		case T_CoerceToDomainValue:
 			return ((CoerceToDomainValue *) expr)->typeMod;
+		case T_SetToDefault:
+			return ((SetToDefault *) expr)->typeMod;
 		default:
 			break;
 	}
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 72dda40d5c93eb56669a29cebe3f7437ac1c493e..eb6683e72f07d566c9d3dcc0ac61f150194667ef 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.105 2003/06/27 17:04:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.106 2003/07/03 16:34:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -178,24 +178,9 @@ transformTargetList(ParseState *pstate, List *targetlist)
 														false));
 			}
 		}
-		else if (IsA(res->val, SetToDefault))
-		{
-			/*
-			 * If this is a DEFAULT element, we make a standard entry using
-			 * the default for the target expression.  rewriteTargetList will
-			 * substitute the columns default for this expression.
-			 */
-			p_target = lappend(p_target,
-							   makeTargetEntry(makeResdom((AttrNumber) pstate->p_next_resno++,
-														  UNKNOWNOID,
-														  -1,
-														  res->name,
-														  false),
-											   (Expr *) res->val));
-		}
 		else
 		{
-			/* Everything else but ColumnRef and SetToDefault */
+			/* Everything else but ColumnRef */
 			p_target = lappend(p_target,
 							   transformTargetEntry(pstate,
 													res->val,
@@ -330,7 +315,6 @@ updateTargetListEntry(ParseState *pstate,
 	Oid			type_id; 		/* type of value provided */
 	Oid			attrtype;		/* type of target column */
 	int32		attrtypmod;
-	bool		isDefault = false;
 	Resdom	   *resnode = tle->resdom;
 	Relation	rd = pstate->p_target_relation;
 
@@ -340,16 +324,26 @@ updateTargetListEntry(ParseState *pstate,
 	attrtype = attnumTypeId(rd, attrno);
 	attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
 
-	/* The type of the default column is equivalent to that of the column */
-	if (tle->expr != NULL && IsA(tle->expr, SetToDefault))
+	/*
+	 * If the expression is a DEFAULT placeholder, insert the attribute's
+	 * type/typmod into it so that exprType will report the right things.
+	 * (We expect that the eventually substituted default expression will
+	 * in fact have this type and typmod.)  Also, reject trying to update
+	 * an array element with DEFAULT, since there can't be any default for
+	 * individual elements of a column.
+	 */
+	if (tle->expr && IsA(tle->expr, SetToDefault))
 	{
-		type_id = attrtype;
-		isDefault = true;
+		SetToDefault   *def = (SetToDefault *) tle->expr;
+
+		def->typeId = attrtype;
+		def->typeMod = attrtypmod;
+		if (indirection)
+			elog(ERROR, "cannot set an array element to DEFAULT");
 	}
 
-	/* Otherwise the expression holds the type */
-	else
-		type_id = exprType((Node *) tle->expr);
+	/* Now we can use exprType() safely. */
+	type_id = exprType((Node *) tle->expr);
 
 	/*
 	 * If there are subscripts on the target column, prepare an array
@@ -401,7 +395,7 @@ updateTargetListEntry(ParseState *pstate,
 		 * coercion.  But accept InvalidOid, which indicates the source is
 		 * a NULL constant.  (XXX is that still true?)
 		 */
-		if (!isDefault && type_id != InvalidOid)
+		if (type_id != InvalidOid)
 		{
 			tle->expr = (Expr *)
 				coerce_to_target_type(pstate,
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 4c1e1247b2c73ade74f814f18302ef080b90166b..a1d9122f828e9146974fa1571ed77e3dbc78078a 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.121 2003/06/25 04:19:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.122 2003/07/03 16:34:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -250,7 +250,9 @@ adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
  * attributes that have defaults and are not assigned to in the given tlist.
  * (We do not insert anything for default-less attributes, however.  The
  * planner will later insert NULLs for them, but there's no reason to slow
- * down rewriter processing with extra tlist nodes.)
+ * down rewriter processing with extra tlist nodes.)  Also, for both INSERT
+ * and UPDATE, replace explicit DEFAULT specifications with column default
+ * expressions.
  *
  * 2. Merge multiple entries for the same target attribute, or declare error
  * if we can't.  Presently, multiple entries are only allowed for UPDATE of
@@ -307,40 +309,49 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
 			{
 				Assert(strcmp(resdom->resname,
 							  NameStr(att_tup->attname)) == 0);
-
-				if (old_tle->expr != NULL && IsA(old_tle->expr, SetToDefault))
-				{
-					/* Set to the default value of the column, as requested */
-					Node	   *new_expr;
-
-					new_expr = build_column_default(target_relation, attrno);
-
-					new_tle = makeTargetEntry(makeResdom(attrno,
-														 att_tup->atttypid,
-														 att_tup->atttypmod,
-											  pstrdup(NameStr(att_tup->attname)),
-														 false),
-											  (Expr *) new_expr);
-				}
-				else
-					/* Normal Case */
-					new_tle = process_matched_tle(old_tle, new_tle);
-
+				new_tle = process_matched_tle(old_tle, new_tle);
 				/* keep scanning to detect multiple assignments to attr */
 			}
 		}
 
-		if (new_tle == NULL && commandType == CMD_INSERT)
+		/*
+		 * Handle the two cases where we need to insert a default expression:
+		 * it's an INSERT and there's no tlist entry for the column, or the
+		 * tlist entry is a DEFAULT placeholder node.
+		 */
+		if ((new_tle == NULL && commandType == CMD_INSERT) ||
+			(new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)))
 		{
-			/*
-			 * Didn't find a matching tlist entry; if it's an INSERT, look
-			 * for a default value, and add a tlist entry computing the
-			 * default if we find one.
-			 */
 			Node	   *new_expr;
 
 			new_expr = build_column_default(target_relation, attrno);
 
+			/*
+			 * If there is no default (ie, default is effectively NULL),
+			 * we can omit the tlist entry in the INSERT case, since the
+			 * planner can insert a NULL for itself, and there's no point
+			 * in spending any more rewriter cycles on the entry.  But in the
+			 * UPDATE case we've got to explicitly set the column to NULL.
+			 */
+			if (!new_expr)
+			{
+				if (commandType == CMD_INSERT)
+					new_tle = NULL;
+				else
+				{
+					new_expr = (Node *) makeConst(att_tup->atttypid,
+												  att_tup->attlen,
+												  (Datum) 0,
+												  true, /* isnull */
+												  att_tup->attbyval);
+					/* this is to catch a NOT NULL domain constraint */
+					new_expr = coerce_to_domain(new_expr,
+												InvalidOid,
+												att_tup->atttypid,
+												COERCE_IMPLICIT_CAST);
+				}
+			}
+
 			if (new_expr)
 				new_tle = makeTargetEntry(makeResdom(attrno,
 													 att_tup->atttypid,
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 63b174a39cf9183eedbc1f39099927356647c7a1..6ff458b91ffcb05d12fca680f4cd5886079e6d81 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *				back to source text
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.143 2003/06/29 00:33:44 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.144 2003/07/03 16:34:25 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -2606,6 +2606,10 @@ get_rule_expr(Node *node, deparse_context *context,
 			appendStringInfo(buf, "VALUE");
 			break;
 
+		case T_SetToDefault:
+			appendStringInfo(buf, "DEFAULT");
+			break;
+
 		default:
 			elog(ERROR, "get_rule_expr: unknown node type %d", nodeTag(node));
 			break;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 2592270c25848d673ebb7148ec343f571ec6c1ec..6e678b26b33178fce20d9b490804167dc20454dc 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.143 2003/06/29 00:33:44 tgl Exp $
+ * $Id: nodes.h,v 1.144 2003/07/03 16:34:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -120,6 +120,7 @@ typedef enum NodeTag
 	T_BooleanTest,
 	T_CoerceToDomain,
 	T_CoerceToDomainValue,
+	T_SetToDefault,
 	T_TargetEntry,
 	T_RangeTblRef,
 	T_JoinExpr,
@@ -279,7 +280,6 @@ typedef enum NodeTag
 	T_PrivGrantee,
 	T_FuncWithArgs,
 	T_PrivTarget,
-	T_SetToDefault,
 	T_CreateOpClassItem,
 	T_CompositeTypeStmt,
 	T_InhRelation,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9101ba1e1776d29a3f6453d45f81f84d300ccff5..5cfe5ec645d20a37c79d36554c0e264bf7260b21 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.242 2003/06/29 00:33:44 tgl Exp $
+ * $Id: parsenodes.h,v 1.243 2003/07/03 16:34:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -278,14 +278,6 @@ typedef struct ResTarget
 								 * assign */
 } ResTarget;
 
-/*
- * Empty node used as a marker for Default Columns
- */
-typedef struct SetToDefault
-{
-	NodeTag		type;
-} SetToDefault;
-
 /*
  * SortGroupBy - for ORDER BY clause
  */
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 57827ee76fe83e20770ba9704f419899c8809583..522ddc5f90233973a3c4452530956e0a78bce778 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.86 2003/06/29 00:33:44 tgl Exp $
+ * $Id: primnodes.h,v 1.87 2003/07/03 16:34:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -674,6 +674,19 @@ typedef struct CoerceToDomainValue
 	int32		typeMod;		/* typemod for substituted value */
 } CoerceToDomainValue;
 
+/*
+ * Placeholder node for a DEFAULT marker in an INSERT or UPDATE command.
+ *
+ * This is not an executable expression: it must be replaced by the actual
+ * column default expression during rewriting.  But it is convenient to
+ * treat it as an expression node during parsing and rewriting.
+ */
+typedef struct SetToDefault
+{
+	Expr		xpr;
+	Oid			typeId;			/* type for substituted value */
+	int32		typeMod;		/* typemod for substituted value */
+} SetToDefault;
 
 /*
  * TargetEntry -