From c8bcd5ca92f812d04f9ded963d812360c6ea20a5 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 24 Jan 2004 23:06:29 +0000
Subject: [PATCH] Fix problems with dropped columns in pltcl triggers, per
 report from Patrick Samson.

---
 doc/src/sgml/pltcl.sgml |  7 +++++--
 src/pl/tcl/pltcl.c      | 40 +++++++++++++++++++++++-----------------
 2 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/doc/src/sgml/pltcl.sgml b/doc/src/sgml/pltcl.sgml
index 22121c2b297..2e7b9f88e18 100644
--- a/doc/src/sgml/pltcl.sgml
+++ b/doc/src/sgml/pltcl.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.28 2003/11/29 19:51:37 pgsql Exp $
+$PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.29 2004/01/24 23:06:29 tgl Exp $
 -->
 
  <chapter id="pltcl">
@@ -516,7 +516,10 @@ SELECT 'doesn''t' AS ret
          element. So looking up a column name in the list with <application>Tcl</>'s
          <function>lsearch</> command returns the element's number starting
 	 with 1 for the first column, the same way the columns are customarily
-	 numbered in <productname>PostgreSQL</productname>.
+	 numbered in <productname>PostgreSQL</productname>.  (Empty list
+	 elements also appear in the positions of columns that have been
+	 dropped, so that the attribute numbering is correct for columns
+	 to their right.)
 	</para>
        </listitem>
       </varlistentry>
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index f813841f2d8..37e515ff66b 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -31,7 +31,7 @@
  *	  ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.81 2004/01/06 23:55:19 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.82 2004/01/24 23:06:29 tgl Exp $
  *
  **********************************************************************/
 
@@ -695,11 +695,15 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 	pfree(stroid);
 
 	/* A list of attribute names for argument TG_relatts */
-	/* note: we deliberately include dropped atts here */
 	Tcl_DStringAppendElement(&tcl_trigtup, "");
 	for (i = 0; i < tupdesc->natts; i++)
-		Tcl_DStringAppendElement(&tcl_trigtup,
-								 NameStr(tupdesc->attrs[i]->attname));
+	{
+		if (tupdesc->attrs[i]->attisdropped)
+			Tcl_DStringAppendElement(&tcl_trigtup, "");
+		else
+			Tcl_DStringAppendElement(&tcl_trigtup,
+									 NameStr(tupdesc->attrs[i]->attname));
+	}
 	Tcl_DStringAppendElement(&tcl_cmd, Tcl_DStringValue(&tcl_trigtup));
 	Tcl_DStringFree(&tcl_trigtup);
 	Tcl_DStringInit(&tcl_trigtup);
@@ -881,9 +885,10 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		siglongjmp(Warn_restart, 1);
 	}
 
-	i = 0;
-	while (i < ret_numvals)
+	for (i = 0; i < ret_numvals; i += 2)
 	{
+		CONST84 char *ret_name = ret_values[i];
+		CONST84 char *ret_value = ret_values[i + 1];
 		int			attnum;
 		HeapTuple	typeTup;
 		Oid			typinput;
@@ -891,24 +896,25 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		FmgrInfo	finfo;
 
 		/************************************************************
-		 * Ignore pseudo elements with a dot name
+		 * Ignore ".tupno" pseudo elements (see pltcl_set_tuple_values)
 		 ************************************************************/
-		if (*(ret_values[i]) == '.')
-		{
-			i += 2;
+		if (strcmp(ret_name, ".tupno") == 0)
 			continue;
-		}
 
 		/************************************************************
 		 * Get the attribute number
 		 ************************************************************/
-		attnum = SPI_fnumber(tupdesc, ret_values[i++]);
+		attnum = SPI_fnumber(tupdesc, ret_name);
 		if (attnum == SPI_ERROR_NOATTRIBUTE)
-			elog(ERROR, "invalid attribute \"%s\"",
-				 ret_values[--i]);
+			elog(ERROR, "invalid attribute \"%s\"", ret_name);
 		if (attnum <= 0)
-			elog(ERROR, "cannot set system attribute \"%s\"",
-				 ret_values[--i]);
+			elog(ERROR, "cannot set system attribute \"%s\"", ret_name);
+
+		/************************************************************
+		 * Ignore dropped columns
+		 ************************************************************/
+		if (tupdesc->attrs[attnum - 1]->attisdropped)
+			continue;
 
 		/************************************************************
 		 * Lookup the attribute type in the syscache
@@ -932,7 +938,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		UTF_BEGIN;
 		modvalues[attnum - 1] =
 			FunctionCall3(&finfo,
-						  CStringGetDatum(UTF_U2E(ret_values[i++])),
+						  CStringGetDatum(UTF_U2E(ret_value)),
 						  ObjectIdGetDatum(typelem),
 				   Int32GetDatum(tupdesc->attrs[attnum - 1]->atttypmod));
 		UTF_END;
-- 
GitLab