diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml
index 35b0699..1f68bdf 100644
--- a/doc/src/sgml/ref/update.sgml
+++ b/doc/src/sgml/ref/update.sgml
@@ -25,7 +25,9 @@ PostgreSQL documentation
 UPDATE [ ONLY ] <replaceable class="PARAMETER">table_name</replaceable> [ * ] [ [ AS ] <replaceable class="parameter">alias</replaceable> ]
     SET { <replaceable class="PARAMETER">column_name</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } |
           ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) |
-          ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) = ( <replaceable class="PARAMETER">sub-SELECT</replaceable> )
+          ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) = ( <replaceable class="PARAMETER">sub-SELECT</replaceable> ) |
+          ( <replaceable class="PARAMETER">*</replaceable> [, ...] ) = ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) |
+          ( <replaceable class="PARAMETER">*</replaceable> [, ...] ) = ( <replaceable class="PARAMETER">sub-SELECT</replaceable> )
         } [, ...]
     [ FROM <replaceable class="PARAMETER">from_list</replaceable> ]
     [ WHERE <replaceable class="PARAMETER">condition</replaceable> | WHERE CURRENT OF <replaceable class="PARAMETER">cursor_name</replaceable> ]
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index bd78e94..9c58f69 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1907,6 +1907,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 	Node	   *qual;
 	ListCell   *origTargetList;
 	ListCell   *tl;
+	bool        isStar = false;
 
 	qry->commandType = CMD_UPDATE;
 	pstate->p_is_update = true;
@@ -1941,6 +1942,51 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 	nsitem->p_lateral_only = false;
 	nsitem->p_lateral_ok = true;
 
+	/* 
+	 * Check if (SET(*) = SELECT ...)  is present. If it is present we 
+	 * resolve and populate the remaining needed MultiAssignRefs in the
+     * target list.
+     */
+	if (list_length(stmt->targetList) == 1)
+	{
+		ResTarget *current_val = linitial(stmt->targetList);
+
+		if (IsA((current_val->val), List))
+		{
+			Node *inner_val = linitial((List *) (current_val->val));
+			List *rel_cols_list;
+			int rteindex = 0;
+			int sublevels_up = 0;
+			int i = 0;
+
+			rteindex = RTERangeTablePosn(pstate, pstate->p_target_rangetblentry,
+										 &sublevels_up);
+
+			expandRTE(pstate->p_target_rangetblentry, rteindex, sublevels_up,
+					  current_val->location, false,
+					  &(rel_cols_list), NULL);
+
+			if (IsA(inner_val, MultiAssignRef))
+			{
+				MultiAssignRef *orig_val = (MultiAssignRef *) (inner_val);
+
+				orig_val->ncolumns = list_length(rel_cols_list);
+
+				for (i = 1;i < list_length(rel_cols_list);i++)
+				{
+					MultiAssignRef *r = makeNode(MultiAssignRef);
+
+					r->source = orig_val->source;
+					r->colno = i + 1;
+					r->ncolumns = orig_val->ncolumns;
+
+					lappend((List *) (current_val->val), r);
+				}
+			}
+		}
+	}
+
+
 	qry->targetList = transformTargetList(pstate, stmt->targetList,
 										  EXPR_KIND_UPDATE_SOURCE);
 
@@ -1986,30 +2032,54 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 			continue;
 		}
 		if (origTargetList == NULL)
-			elog(ERROR, "UPDATE target count mismatch --- internal error");
-		origTarget = (ResTarget *) lfirst(origTargetList);
-		Assert(IsA(origTarget, ResTarget));
+		{
+			if (!isStar)
+				elog(ERROR, "UPDATE target count mismatch --- internal error");
+		}
+		else
+		{
+			origTarget = (ResTarget *) lfirst(origTargetList);
+			Assert(IsA(origTarget, ResTarget));
+		}
 
-		attrno = attnameAttNum(pstate->p_target_relation,
-							   origTarget->name, true);
-		if (attrno == InvalidAttrNumber)
-			ereport(ERROR,
-					(errcode(ERRCODE_UNDEFINED_COLUMN),
-					 errmsg("column \"%s\" of relation \"%s\" does not exist",
-							origTarget->name,
-						 RelationGetRelationName(pstate->p_target_relation)),
-					 parser_errposition(pstate, origTarget->location)));
+		if (!(origTarget) || !(origTarget->name))
+			isStar = true;
 
-		updateTargetListEntry(pstate, tle, origTarget->name,
-							  attrno,
-							  origTarget->indirection,
-							  origTarget->location);
+		if (!isStar)
+			attrno = attnameAttNum(pstate->p_target_relation,
+								   origTarget->name, true);
+		else
+			attrno = attnameAttNum(pstate->p_target_relation,
+								   tle->resname, true);
+
+		/*
+		 * Check only if we do not have SET (*) else the expansion happened
+		 * with relation's attribute names.
+		 * No need for updating target list entry for SET (*) since it is already
+		 * processed.
+		 */
+		if (!isStar)
+		{
+			if (attrno == InvalidAttrNumber)
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_COLUMN),
+						 errmsg("column \"%s\" of relation \"%s\" does not exist",
+								origTarget->name,
+								RelationGetRelationName(pstate->p_target_relation)),
+						 parser_errposition(pstate, origTarget->location)));
+
+			updateTargetListEntry(pstate, tle, origTarget->name,
+								  attrno,
+								  origTarget->indirection,
+								  origTarget->location);
+		}
 
 		/* Mark the target column as requiring update permissions */
 		target_rte->modifiedCols = bms_add_member(target_rte->modifiedCols,
 								attrno - FirstLowInvalidHeapAttributeNumber);
 
-		origTargetList = lnext(origTargetList);
+		if (origTargetList)
+			origTargetList = lnext(origTargetList);
 	}
 	if (origTargetList != NULL)
 		elog(ERROR, "UPDATE target count mismatch --- internal error");
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c98c27a..c2bad88 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -9485,6 +9485,45 @@ multiple_set_clause:
 
 					$$ = $2;
 				}
+            | '(' '*' ')' '=' ctext_row
+			    {
+					ResTarget *res_col = makeNode(ResTarget);
+
+					/* Make a single node having all target values in a list */
+					res_col->val = (Node *) $5;
+					res_col->location = @2;
+
+					$$ = list_make1(res_col);
+				}
+            | '(' '*' ')' '=' select_with_parens
+				{
+					SubLink *sl = makeNode(SubLink);
+					int ncolumns = -1;  /* We do not know the number of columns yet */
+
+					/* 
+					 * Create a MultiAssignRef source as representative for the entire set
+					 * since we cannot look up attributes of target relation here.
+					 */
+					ResTarget *res_col = makeNode(ResTarget);
+					MultiAssignRef *r = makeNode(MultiAssignRef);
+
+					/* First, convert bare SelectStmt into a SubLink */
+					sl->subLinkType = MULTIEXPR_SUBLINK;
+					sl->subLinkId = 0;		/* will be assigned later */
+					sl->testexpr = NULL;
+					sl->operName = NIL;
+					sl->subselect = $5;
+					sl->location = @5;
+
+					r->source = (Node *) sl;
+					r->colno = 1;
+					r->ncolumns = ncolumns;
+					res_col->val = (Node *) list_make1(r);
+
+					res_col->location = @2;
+
+					$$ = list_make1(res_col);
+				}
 		;
 
 set_target:
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 4a8aaf6..4e371e8 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -1295,7 +1295,7 @@ transformMultiAssignRef(ParseState *pstate, MultiAssignRef *maref)
 		Assert(IsA(qtree, Query));
 
 		/* Check subquery returns required number of columns */
-		if (count_nonjunk_tlist_entries(qtree->targetList) != maref->ncolumns)
+		if ((count_nonjunk_tlist_entries(qtree->targetList) != maref->ncolumns) && maref->ncolumns != -1)
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("number of columns does not match number of values"),
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 328e0c6..5947611 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -20,6 +20,7 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
+#include "nodes/value.h"
 #include "parser/parsetree.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
@@ -123,6 +124,7 @@ transformTargetList(ParseState *pstate, List *targetlist,
 {
 	List	   *p_target = NIL;
 	ListCell   *o_target;
+	bool       isStar = false;
 
 	/* Shouldn't have any leftover multiassign items at start */
 	Assert(pstate->p_multiassign_exprs == NIL);
@@ -162,17 +164,110 @@ transformTargetList(ParseState *pstate, List *targetlist,
 				continue;
 			}
 		}
+		else if (IsA(res->val, List))
+		{
+			List *rel_cols_list;
+			ListCell *lc;
+			ListCell *lc_cols;
+			int rteindex;
+			int sublevels_up;
 
-		/*
-		 * Not "something.*", so transform as a single expression
-		 */
-		p_target = lappend(p_target,
-						   transformTargetEntry(pstate,
-												res->val,
-												NULL,
-												exprKind,
-												res->name,
-												false));
+			/* SET (*) = ... is present */
+			isStar = true;
+
+			rteindex = RTERangeTablePosn(pstate, pstate->p_target_rangetblentry,
+										 &sublevels_up);
+
+			expandRTE(pstate->p_target_rangetblentry, rteindex, sublevels_up,
+					  res->location, false,
+					  &(rel_cols_list), NULL);
+
+			if (list_length(rel_cols_list) != list_length((List *)(res->val)))
+				elog(ERROR, "number of columns does not match number of values");
+
+			forboth(lc, (List *) (res->val), lc_cols, rel_cols_list)
+			{
+				Node *current_val = lfirst(lc);
+				char *current_resname = strVal(lfirst(lc_cols));
+
+				/*
+				 * Check for "something.*".  Depending on the complexity of the
+				 * "something", the star could appear as the last field in ColumnRef,
+				 * or as the last indirection item in A_Indirection.
+				 */
+				if (IsA(current_val, ColumnRef))
+				{
+					ColumnRef  *cref = (ColumnRef *) current_val;
+
+					if (IsA(llast(cref->fields), A_Star))
+					{
+						List *current_result = ExpandColumnRefStar(pstate, cref,
+																   true);
+						ListCell *lc_result;
+
+						/* It is something.*, expand into multiple items */
+						foreach(lc_result, current_result)
+						{
+							TargetEntry *tle_current = lfirst(lc_result);
+
+							tle_current->resname = current_resname;
+						}
+
+						p_target = list_concat(p_target, current_result);
+						continue;
+					}
+				}
+				else if (IsA(current_val, A_Indirection))
+				{
+					A_Indirection *ind = (A_Indirection *) current_val;
+
+					if (IsA(llast(ind->indirection), A_Star))
+					{
+						List *current_result = ExpandIndirectionStar(pstate, ind,
+																	 true, exprKind);
+						ListCell *lc_result;
+
+						/* It is something.*, expand into multiple items */
+						foreach(lc_result, current_result)
+						{
+							TargetEntry *tle_current = lfirst(lc_result);
+
+							tle_current->resname = current_resname;
+						}
+
+						p_target = list_concat(p_target,
+											   current_result);
+						continue;
+					}
+				}
+
+				/*
+				 * Not "something.*", so transform as a single expression
+				 */
+				p_target = lappend(p_target,
+								   transformTargetEntry(pstate,
+														current_val,
+														NULL,
+														exprKind,
+														current_resname,
+														false));
+			}
+		}
+
+		if (!isStar)
+		{
+			/*
+			 * Not "SET (*) =... " and "something.*",
+			 * so transform as a single expression
+			 */
+			p_target = lappend(p_target,
+							   transformTargetEntry(pstate,
+													res->val,
+													NULL,
+													exprKind,
+													res->name,
+													false));
+		}
 	}
 
 	/*
