From 21591967bc19c749a100fb97ec82f6086ce5cc3c Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 5 Mar 2003 20:01:04 +0000
Subject: [PATCH] Turns out new IN implementation has got some problems in an
 UPDATE or DELETE with inherited target table.  Fix it; add a regression test.
 Also, correct ancient misspelling of 'inherited'.

---
 src/backend/nodes/copyfuncs.c          | 14 +++++++-----
 src/backend/nodes/equalfuncs.c         | 12 +++++-----
 src/backend/optimizer/path/allpaths.c  |  4 ++--
 src/backend/optimizer/plan/planner.c   |  6 ++---
 src/backend/optimizer/prep/prepunion.c |  6 ++---
 src/include/optimizer/prep.h           |  4 ++--
 src/test/regress/expected/inherit.out  | 31 ++++++++++++++++++++++++++
 src/test/regress/sql/inherit.sql       | 23 +++++++++++++++++++
 8 files changed, 80 insertions(+), 20 deletions(-)

diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 2698f084787..627f62c84f8 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.244 2003/02/16 02:30:37 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.245 2003/03/05 20:01:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1481,12 +1481,16 @@ _copyQuery(Query *from)
 	COPY_NODE_FIELD(limitCount);
 	COPY_NODE_FIELD(setOperations);
 	COPY_INTLIST_FIELD(resultRelations);
+	COPY_NODE_FIELD(in_info_list);
+	COPY_SCALAR_FIELD(hasJoinRTEs);
 
 	/*
-	 * We do not copy the planner internal fields: base_rel_list,
-	 * other_rel_list, join_rel_list, equi_key_list, in_info_list,
-	 * query_pathkeys, hasJoinRTEs.  That would get us into copying
-	 * RelOptInfo/Path trees, which we don't want to do.
+	 * We do not copy the other planner internal fields: base_rel_list,
+	 * other_rel_list, join_rel_list, equi_key_list, query_pathkeys.
+	 * That would get us into copying RelOptInfo/Path trees, which we don't
+	 * want to do.  It is necessary to copy in_info_list and hasJoinRTEs
+	 * for the benefit of inheritance_planner(), which may try to copy a
+	 * Query in which these are already set.
 	 */
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 378d8e44031..6a0f3660097 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.187 2003/02/16 02:30:37 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.188 2003/03/05 20:01:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -576,12 +576,14 @@ _equalQuery(Query *a, Query *b)
 	COMPARE_NODE_FIELD(limitCount);
 	COMPARE_NODE_FIELD(setOperations);
 	COMPARE_INTLIST_FIELD(resultRelations);
+	COMPARE_NODE_FIELD(in_info_list);
+	COMPARE_SCALAR_FIELD(hasJoinRTEs);
 
 	/*
-	 * We do not check the internal-to-the-planner fields: base_rel_list,
-	 * other_rel_list, join_rel_list, equi_key_list, in_info_list,
-	 * query_pathkeys, hasJoinRTEs.  They might not be set yet, and in any
-	 * case they should be derivable from the other fields.
+	 * We do not check the other planner internal fields: base_rel_list,
+	 * other_rel_list, join_rel_list, equi_key_list, query_pathkeys.
+	 * They might not be set yet, and in any case they should be derivable
+	 * from the other fields.
 	 */
 	return true;
 }
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 24a604716b8..99d979d57c0 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.97 2003/02/15 20:12:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.98 2003/03/05 20:01:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -115,7 +115,7 @@ set_base_rel_pathlists(Query *root)
 			/* RangeFunction --- generate a separate plan for it */
 			set_function_pathlist(root, rel, rte);
 		}
-		else if ((inheritlist = expand_inherted_rtentry(root, rti, true))
+		else if ((inheritlist = expand_inherited_rtentry(root, rti, true))
 				 != NIL)
 		{
 			/* Relation is root of an inheritance tree, process specially */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index c597e44f1d4..c7c072fe2eb 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.149 2003/03/05 18:38:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.150 2003/03/05 20:01:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -276,8 +276,8 @@ subquery_planner(Query *parse, double tuple_fraction)
 	 * grouping_planner.
 	 */
 	if (parse->resultRelation &&
-	 (lst = expand_inherted_rtentry(parse, parse->resultRelation, false))
-		!= NIL)
+		(lst = expand_inherited_rtentry(parse, parse->resultRelation,
+										false)) != NIL)
 		plan = inheritance_planner(parse, lst);
 	else
 		plan = grouping_planner(parse, tuple_fraction);
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 0f63d2306c7..f0a64f2980c 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.90 2003/02/09 06:56:27 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.91 2003/03/05 20:01:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -642,7 +642,7 @@ find_all_inheritors(Oid parentrel)
 }
 
 /*
- * expand_inherted_rtentry
+ * expand_inherited_rtentry
  *		Check whether a rangetable entry represents an inheritance set.
  *		If so, add entries for all the child tables to the query's
  *		rangetable, and return an integer list of RT indexes for the
@@ -666,7 +666,7 @@ find_all_inheritors(Oid parentrel)
  * XXX probably should convert the result type to Relids?
  */
 List *
-expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
+expand_inherited_rtentry(Query *parse, Index rti, bool dup_parent)
 {
 	RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
 	Oid			parentOID;
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index 681d1c2eb1d..5cde6096a1e 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.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: prep.h,v 1.37 2003/02/09 23:57:19 tgl Exp $
+ * $Id: prep.h,v 1.38 2003/03/05 20:01:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,7 +52,7 @@ extern Plan *plan_set_operations(Query *parse);
 
 extern List *find_all_inheritors(Oid parentrel);
 
-extern List *expand_inherted_rtentry(Query *parse, Index rti,
+extern List *expand_inherited_rtentry(Query *parse, Index rti,
 						bool dup_parent);
 
 extern Node *adjust_inherited_attrs(Node *node,
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 6ca59e799bf..e6fc8bcb575 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -539,3 +539,34 @@ CREATE TEMP TABLE z (b TEXT, PRIMARY KEY(aa, b)) inherits (a);
 NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 'z_pkey' for table 'z'
 INSERT INTO z VALUES (NULL, 'text'); -- should fail
 ERROR:  ExecInsert: Fail to add null value in not null attribute aa
+-- Check UPDATE with inherited target and an inherited source table
+create temp table foo(f1 int, f2 int);
+create temp table foo2(f3 int) inherits (foo);
+create temp table bar(f1 int, f2 int);
+create temp table bar2(f3 int) inherits (bar);
+insert into foo values(1,1);
+insert into foo values(3,3);
+insert into foo2 values(2,2,2);
+insert into foo2 values(3,3,3);
+insert into bar values(1,1);
+insert into bar values(2,2);
+insert into bar values(3,3);
+insert into bar values(4,4);
+insert into bar2 values(1,1,1);
+insert into bar2 values(2,2,2);
+insert into bar2 values(3,3,3);
+insert into bar2 values(4,4,4);
+update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
+SELECT relname, bar.* FROM bar, pg_class where bar.tableoid = pg_class.oid;
+ relname | f1 | f2  
+---------+----+-----
+ bar     |  4 |   4
+ bar     |  1 | 101
+ bar     |  2 | 102
+ bar     |  3 | 103
+ bar2    |  4 |   4
+ bar2    |  1 | 101
+ bar2    |  2 | 102
+ bar2    |  3 | 103
+(8 rows)
+
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index d8d73f8860f..a50b5e75f93 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -96,3 +96,26 @@ SELECT relname, d.* FROM ONLY d, pg_class where d.tableoid = pg_class.oid;
 -- Confirm PRIMARY KEY adds NOT NULL constraint to child table
 CREATE TEMP TABLE z (b TEXT, PRIMARY KEY(aa, b)) inherits (a);
 INSERT INTO z VALUES (NULL, 'text'); -- should fail
+
+-- Check UPDATE with inherited target and an inherited source table
+create temp table foo(f1 int, f2 int);
+create temp table foo2(f3 int) inherits (foo);
+create temp table bar(f1 int, f2 int);
+create temp table bar2(f3 int) inherits (bar);
+
+insert into foo values(1,1);
+insert into foo values(3,3);
+insert into foo2 values(2,2,2);
+insert into foo2 values(3,3,3);
+insert into bar values(1,1);
+insert into bar values(2,2);
+insert into bar values(3,3);
+insert into bar values(4,4);
+insert into bar2 values(1,1,1);
+insert into bar2 values(2,2,2);
+insert into bar2 values(3,3,3);
+insert into bar2 values(4,4,4);
+
+update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
+
+SELECT relname, bar.* FROM bar, pg_class where bar.tableoid = pg_class.oid;
-- 
GitLab