diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 08c209b2a5dd0a0876ebfa80c78d7ee1a988ea8c..2bd3a00b73e9656a52bc33124aaa4c056a60b670 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: analyze.c,v 1.121 1999/10/07 04:23:11 tgl Exp $
+ *	$Id: analyze.c,v 1.122 1999/11/01 05:06:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -253,6 +253,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 	Query	   *qry = makeNode(Query);
 	Node	   *fromQual;
 	List	   *icolumns;
+	List	   *attrnos;
+	List	   *attnos;
+	int			numuseratts;
 	List	   *tl;
 	TupleDesc	rd_att;
 
@@ -333,9 +336,11 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 		pstate->p_last_resno = pstate->p_target_relation->rd_rel->relnatts + 1;
 
 	/* Validate stmt->cols list, or build default list if no list given */
-	icolumns = makeTargetNames(pstate, stmt->cols);
+	icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);
 
 	/* Prepare non-junk columns for assignment to target table */
+	numuseratts = 0;
+	attnos = attrnos;
 	foreach(tl, qry->targetList)
 	{
 		TargetEntry *tle = (TargetEntry *) lfirst(tl);
@@ -352,16 +357,30 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 			resnode->resno = (AttrNumber) pstate->p_last_resno++;
 			continue;
 		}
-		if (icolumns == NIL)
+		if (icolumns == NIL || attnos == NIL)
 			elog(ERROR, "INSERT has more expressions than target columns");
 		id = (Ident *) lfirst(icolumns);
-		updateTargetListEntry(pstate, tle, id->name, id->indirection);
+		updateTargetListEntry(pstate, tle, id->name, lfirsti(attnos),
+							  id->indirection);
+		numuseratts++;
 		icolumns = lnext(icolumns);
+		attnos = lnext(attnos);
 	}
 
+	/*
+	 * It is possible that the targetlist has fewer entries than were in
+	 * the columns list.  We do not consider this an error (perhaps we
+	 * should, if the columns list was explictly given?).  We must truncate
+	 * the attrnos list to only include the attrs actually provided,
+	 * else we will fail to apply defaults for them below.
+	 */
+	if (icolumns != NIL)
+		attrnos = ltruncate(numuseratts, attrnos);
+
 	/*
 	 * Add targetlist items to assign DEFAULT values to any columns that
 	 * have defaults and were not assigned to by the user.
+	 *
 	 * XXX wouldn't it make more sense to do this further downstream,
 	 * after the rule rewriter?
 	 */
@@ -372,29 +391,20 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 		AttrDefault *defval = rd_att->constr->defval;
 		int			ndef = rd_att->constr->num_defval;
 
-		while (ndef-- > 0)
+		while (--ndef >= 0)
 		{
-			Form_pg_attribute thisatt = att[defval[ndef].adnum - 1];
-			TargetEntry *te;
+			AttrNumber		attrno = defval[ndef].adnum;
+			Form_pg_attribute thisatt = att[attrno - 1];
+			TargetEntry	   *te;
 
-			foreach(tl, qry->targetList)
-			{
-				TargetEntry *tle = (TargetEntry *) lfirst(tl);
-				Resdom	   *resnode = tle->resdom;
-
-				if (resnode->resjunk)
-					continue;	/* ignore resjunk nodes */
-				if (namestrcmp(&(thisatt->attname), resnode->resname) == 0)
-					break;
-			}
-			if (tl != NIL)		/* found TLE for this attr */
-				continue;
+			if (intMember((int) attrno, attrnos))
+				continue;		/* there was a user-specified value */
 			/*
 			 * No user-supplied value, so add a targetentry with DEFAULT expr
 			 * and correct data for the target column.
 			 */
 			te = makeTargetEntry(
-				makeResdom(defval[ndef].adnum,
+				makeResdom(attrno,
 						   thisatt->atttypid,
 						   thisatt->atttypmod,
 						   pstrdup(nameout(&(thisatt->attname))),
@@ -405,7 +415,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 			 * Make sure the value is coerced to the target column type
 			 * (might not be right type if it's not a constant!)
 			 */
-			updateTargetListEntry(pstate, te, te->resdom->resname, NIL);
+			updateTargetListEntry(pstate, te, te->resdom->resname, attrno,
+								  NIL);
 		}
 	}
 
@@ -1128,8 +1139,10 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 		if (origTargetList == NIL)
 			elog(ERROR, "UPDATE target count mismatch --- internal error");
 		origTarget = (ResTarget *) lfirst(origTargetList);
-		updateTargetListEntry(pstate, tle,
-							  origTarget->name, origTarget->indirection);
+		updateTargetListEntry(pstate, tle, origTarget->name,
+							  attnameAttNum(pstate->p_target_relation,
+											origTarget->name),
+							  origTarget->indirection);
 		origTargetList = lnext(origTargetList);
 	}
 	if (origTargetList != NIL)
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 35fa858dc0888931da341c97d3d33af95bac520e..d4593a1357b3c1d30b939d4d393e902e8656ccb1 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.31 1999/08/23 23:48:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.32 1999/11/01 05:06:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -176,11 +176,16 @@ make_op(char *opname, Node *ltree, Node *rtree)
 }	/* make_op() */
 
 
+/*
+ * make_var
+ *		Build a Var node for an attribute identified by name
+ */
 Var *
 make_var(ParseState *pstate, Oid relid, char *refname,
 		 char *attrname)
 {
-	Var		   *varnode;
+	HeapTuple	tp;
+	Form_pg_attribute att_tup;
 	int			vnum,
 				attid;
 	Oid			vartypeid;
@@ -189,16 +194,19 @@ make_var(ParseState *pstate, Oid relid, char *refname,
 
 	vnum = refnameRangeTablePosn(pstate, refname, &sublevels_up);
 
-	attid = get_attnum(relid, attrname);
-	if (attid == InvalidAttrNumber)
+	tp = SearchSysCacheTuple(ATTNAME,
+							 ObjectIdGetDatum(relid),
+							 PointerGetDatum(attrname),
+							 0, 0);
+	if (!HeapTupleIsValid(tp))
 		elog(ERROR, "Relation %s does not have attribute %s",
 			 refname, attrname);
-	vartypeid = get_atttype(relid, attid);
-	type_mod = get_atttypmod(relid, attid);
-
-	varnode = makeVar(vnum, attid, vartypeid, type_mod, sublevels_up);
+	att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+	attid = att_tup->attnum;
+	vartypeid = att_tup->atttypid;
+	type_mod = att_tup->atttypmod;
 
-	return varnode;
+	return makeVar(vnum, attid, vartypeid, type_mod, sublevels_up);
 }
 
 /*
@@ -380,67 +388,73 @@ transformArraySubscripts(ParseState *pstate,
 }
 
 /*
- * make_const -
+ * make_const
  *
- * - takes a lispvalue, (as returned to the yacc routine by the lexer)
- *	 extracts the type, and makes the appropriate type constant
- *	 by invoking the (c-callable) lisp routine c-make-const
- *	 via the lisp_call() mechanism
- *
- * eventually, produces a "const" lisp-struct as per nodedefs.cl
+ *	Convert a Value node (as returned by the grammar) to a Const node
+ *	of the "natural" type for the constant.  For strings we produce
+ *	a constant of type UNKNOWN ---- representation is the same as text,
+ *	but this indicates to later type resolution that we're not sure that
+ *	it should be considered text.
  */
 Const *
 make_const(Value *value)
 {
-	Type		tp;
 	Datum		val;
+	Oid			typeid;
+	int			typelen;
+	bool		typebyval;
 	Const	   *con;
 
 	switch (nodeTag(value))
 	{
 		case T_Integer:
-			tp = typeidType(INT4OID);
 			val = Int32GetDatum(intVal(value));
+
+			typeid = INT4OID;
+			typelen = sizeof(int32);
+			typebyval = true;
 			break;
 
 		case T_Float:
 			{
 				float64		dummy;
 
-				tp = typeidType(FLOAT8OID);
-
 				dummy = (float64) palloc(sizeof(float64data));
 				*dummy = floatVal(value);
 
 				val = Float64GetDatum(dummy);
+
+				typeid = FLOAT8OID;
+				typelen = sizeof(float64data);
+				typebyval = false;
 			}
 			break;
 
 		case T_String:
-			tp = typeidType(UNKNOWNOID);		/* unknown for now, will
-												 * be type coerced */
 			val = PointerGetDatum(textin(strVal(value)));
+
+			typeid = UNKNOWNOID; /* will be coerced later */
+			typelen = -1;		/* variable len */
+			typebyval = false;
 			break;
 
 		case T_Null:
 		default:
-			{
-				if (nodeTag(value) != T_Null)
-					elog(NOTICE, "make_const: unknown type %d\n", nodeTag(value));
+			if (nodeTag(value) != T_Null)
+				elog(NOTICE, "make_const: unknown type %d\n", nodeTag(value));
 
-				/* null const */
-				con = makeConst(0, 0, (Datum) NULL, true, false, false, false);
-				return con;
-			}
+			/* return a null const */
+			con = makeConst(0, 0, (Datum) NULL, true, false, false, false);
+			return con;
 	}
 
-	con = makeConst(typeTypeId(tp),
-					typeLen(tp),
+	con = makeConst(typeid,
+					typelen,
 					val,
 					false,
-					typeByVal(tp),
+					typebyval,
 					false,		/* not a set */
-					false);
+					false);		/* not coerced */
 
 	return con;
 }
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 48973f67d9b928a7532ab2688d4dd45076e661b4..a009bc5a77cc554ee847de2f78a9f3a9f4c9465e 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.46 1999/07/19 00:26:20 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.47 1999/11/01 05:06:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -162,12 +162,14 @@ transformTargetList(ParseState *pstate, List *targetlist)
  * pstate		parse state
  * tle			target list entry to be modified
  * colname		target column name (ie, name of attribute to be assigned to)
+ * attrno		target attribute number
  * indirection	subscripts for target column, if any
  */
 void
 updateTargetListEntry(ParseState *pstate,
 					  TargetEntry *tle,
 					  char *colname,
+					  int attrno,
 					  List *indirection)
 {
 	Oid			type_id = exprType(tle->expr); /* type of value provided */
@@ -175,14 +177,12 @@ updateTargetListEntry(ParseState *pstate,
 	int32		attrtypmod;
 	Resdom	   *resnode = tle->resdom;
 	Relation	rd = pstate->p_target_relation;
-	int			resdomno;
 
 	Assert(rd != NULL);
-	resdomno = attnameAttNum(rd, colname);
-	if (resdomno <= 0)
+	if (attrno <= 0)
 		elog(ERROR, "Cannot assign to system attribute '%s'", colname);
-	attrtype = attnumTypeId(rd, resdomno);
-	attrtypmod = rd->rd_att->attrs[resdomno - 1]->atttypmod;
+	attrtype = attnumTypeId(rd, attrno);
+	attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
 
 	/*
 	 * If there are subscripts on the target column, prepare an
@@ -260,7 +260,7 @@ updateTargetListEntry(ParseState *pstate,
 	resnode->restype = attrtype;
 	resnode->restypmod = attrtypmod;
 	resnode->resname = colname;
-	resnode->resno = (AttrNumber) resdomno;
+	resnode->resno = (AttrNumber) attrno;
 }
 
 
@@ -356,14 +356,17 @@ SizeTargetExpr(ParseState *pstate,
 
 
 /*
- * makeTargetNames -
+ * checkInsertTargets -
  *	  generate a list of column names if not supplied or
  *	  test supplied column names to make sure they are in target table.
+ *	  Also return an integer list of the columns' attribute numbers.
  *	  (used exclusively for inserts)
  */
 List *
-makeTargetNames(ParseState *pstate, List *cols)
+checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
 {
+	*attrnos = NIL;
+
 	if (cols == NIL)
 	{
 		/*
@@ -382,6 +385,7 @@ makeTargetNames(ParseState *pstate, List *cols)
 			id->indirection = NIL;
 			id->isRel = false;
 			cols = lappend(cols, id);
+			*attrnos = lappendi(*attrnos, i+1);
 		}
 	}
 	else
@@ -394,17 +398,14 @@ makeTargetNames(ParseState *pstate, List *cols)
 		foreach(tl, cols)
 		{
 			char	   *name = ((Ident *) lfirst(tl))->name;
-			List	   *nxt;
+			int			attrno;
 
 			/* Lookup column name, elog on failure */
-			attnameAttNum(pstate->p_target_relation, name);
+			attrno = attnameAttNum(pstate->p_target_relation, name);
 			/* Check for duplicates */
-			foreach(nxt, lnext(tl))
-			{
-				if (strcmp(name, ((Ident *) lfirst(nxt))->name) == 0)
-					elog(ERROR, "Attribute '%s' specified more than once",
-						 name);
-			}
+			if (intMember(attrno, *attrnos))
+				elog(ERROR, "Attribute '%s' specified more than once", name);
+			*attrnos = lappendi(*attrnos, attrno);
 		}
 	}
 
diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h
index c2babecb769d9e1b9b257fbc58420c157132db00..08cf389d72e61671edcb3a2c4a78e8489f22b42d 100644
--- a/src/include/parser/parse_target.h
+++ b/src/include/parser/parse_target.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_target.h,v 1.15 1999/07/19 00:26:18 tgl Exp $
+ * $Id: parse_target.h,v 1.16 1999/11/01 05:06:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,9 +20,11 @@ extern TargetEntry *transformTargetEntry(ParseState *pstate,
 										 Node *node, Node *expr,
 										 char *colname, bool resjunk);
 extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
-								  char *colname, List *indirection);
+								  char *colname, int attrno,
+								  List *indirection);
 extern Node *CoerceTargetExpr(ParseState *pstate, Node *expr,
 							  Oid type_id, Oid attrtype);
-extern List *makeTargetNames(ParseState *pstate, List *cols);
+extern List *checkInsertTargets(ParseState *pstate, List *cols,
+								List **attrnos);
 
 #endif	 /* PARSE_TARGET_H */