From 134fdf34d6c48e6420f7592a6b1e02adcf0f2d02 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 12 Aug 2000 04:04:53 +0000
Subject: [PATCH] Fix ruleutils to produce correct output for array assignment,
 such as UPDATE foo SET arr[3] = 42.

---
 src/backend/utils/adt/ruleutils.c | 54 ++++++++++++++++++++++++++++---
 1 file changed, 50 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 6d4da07207a..7d44657429d 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *			  out of its tuple
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.58 2000/08/08 15:42:21 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.59 2000/08/12 04:04:53 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -107,6 +107,7 @@ static void get_func_expr(Expr *expr, deparse_context *context);
 static void get_tle_expr(TargetEntry *tle, deparse_context *context);
 static void get_const_expr(Const *constval, deparse_context *context);
 static void get_sublink_expr(Node *node, deparse_context *context);
+static bool tleIsArrayAssign(TargetEntry *tle);
 static char *quote_identifier(char *ident);
 static char *get_relation_name(Oid relid);
 static char *get_attribute_name(Oid relid, int2 attnum);
@@ -1186,8 +1187,14 @@ get_update_query_def(Query *query, deparse_context *context)
 
 		appendStringInfo(buf, sep);
 		sep = ", ";
-		appendStringInfo(buf, "%s = ",
-						 quote_identifier(tle->resdom->resname));
+		/*
+		 * If the update expression is an array assignment, we mustn't
+		 * put out "attname =" here; it will come out of the display
+		 * of the ArrayRef node instead.
+		 */
+		if (! tleIsArrayAssign(tle))
+			appendStringInfo(buf, "%s = ",
+							 quote_identifier(tle->resdom->resname));
 		get_tle_expr(tle, context);
 	}
 
@@ -1409,10 +1416,20 @@ get_rule_expr(Node *node, deparse_context *context)
 		case T_ArrayRef:
 			{
 				ArrayRef   *aref = (ArrayRef *) node;
+				bool		savevarprefix = context->varprefix;
 				List	   *lowlist;
 				List	   *uplist;
 
+				/*
+				 * If we are doing UPDATE array[n] = expr, we need to
+				 * suppress any prefix on the array name.  Currently,
+				 * that is the only context in which we will see a non-null
+				 * refassgnexpr --- but someday a smarter test may be needed.
+				 */
+				if (aref->refassgnexpr)
+					context->varprefix = false;
 				get_rule_expr(aref->refexpr, context);
+				context->varprefix = savevarprefix;
 				lowlist = aref->reflowerindexpr;
 				foreach(uplist, aref->refupperindexpr)
 				{
@@ -1426,7 +1443,11 @@ get_rule_expr(Node *node, deparse_context *context)
 					get_rule_expr((Node *) lfirst(uplist), context);
 					appendStringInfo(buf, "]");
 				}
-				/* XXX need to do anything with refassgnexpr? */
+				if (aref->refassgnexpr)
+				{
+					appendStringInfo(buf, " = ");
+					get_rule_expr(aref->refassgnexpr, context);
+				}
 			}
 			break;
 
@@ -1842,6 +1863,31 @@ get_sublink_expr(Node *node, deparse_context *context)
 		appendStringInfoChar(buf, ')');
 }
 
+/* ----------
+ * tleIsArrayAssign			- check for array assignment
+ * ----------
+ */
+static bool
+tleIsArrayAssign(TargetEntry *tle)
+{
+	ArrayRef   *aref;
+
+	if (tle->expr == NULL || !IsA(tle->expr, ArrayRef))
+		return false;
+	aref = (ArrayRef *) tle->expr;
+	if (aref->refassgnexpr == NULL)
+		return false;
+	/*
+	 * Currently, it should only be possible to see non-null refassgnexpr
+	 * if we are indeed looking at an "UPDATE array[n] = expr" situation.
+	 * So aref->refexpr ought to match the tle's target.
+	 */
+	if (aref->refexpr == NULL || !IsA(aref->refexpr, Var) ||
+		((Var *) aref->refexpr)->varno != tle->resdom->resno)
+		elog(NOTICE, "tleIsArrayAssign: I'm confused ...");
+	return true;
+}
+
 /* ----------
  * quote_identifier			- Quote an identifier only if needed
  *
-- 
GitLab