Fix partitioning crashes during error reporting.
authorRobert Haas <rhaas@postgresql.org>
Mon, 24 Jul 2017 22:08:08 +0000 (18:08 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 24 Jul 2017 22:08:08 +0000 (18:08 -0400)
In various places where we reverse-map a tuple before calling
ExecBuildSlotValueDescription, we neglected to ensure that the
slot descriptor matched the tuple stored in it.

Amit Langote and Amit Khandekar, reviewed by Etsuro Fujita

Discussion: http://postgr.es/m/CAJ3gD9cqpP=WvJj=dv1ONkPWjy8ZuUaOM4_x86i3uQPas=0_jg@mail.gmail.com

src/backend/executor/execMain.c
src/test/regress/expected/insert.out
src/test/regress/expected/updatable_views.out
src/test/regress/sql/insert.sql
src/test/regress/sql/updatable_views.sql

index b22de78516731e6de3a2f9d43ba61c2c3b1a4ccd..78cbcd1a324170933f37cfddd5efbbf1b855372e 100644 (file)
@@ -1879,6 +1879,7 @@ ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
            if (map != NULL)
            {
                tuple = do_convert_tuple(tuple, map);
+               ExecSetSlotDescriptor(slot, tupdesc);
                ExecStoreTuple(tuple, slot, InvalidBuffer, false);
            }
        }
@@ -1956,6 +1957,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
                    if (map != NULL)
                    {
                        tuple = do_convert_tuple(tuple, map);
+                       ExecSetSlotDescriptor(slot, tupdesc);
                        ExecStoreTuple(tuple, slot, InvalidBuffer, false);
                    }
                }
@@ -2003,6 +2005,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
                if (map != NULL)
                {
                    tuple = do_convert_tuple(tuple, map);
+                   ExecSetSlotDescriptor(slot, tupdesc);
                    ExecStoreTuple(tuple, slot, InvalidBuffer, false);
                }
            }
@@ -2112,6 +2115,7 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
                        if (map != NULL)
                        {
                            tuple = do_convert_tuple(tuple, map);
+                           ExecSetSlotDescriptor(slot, tupdesc);
                            ExecStoreTuple(tuple, slot, InvalidBuffer, false);
                        }
                    }
index c608ce377f6dfae44ba04e4974c9bc07780e1843..0dcc86fef48b5194d988cd87f50b60bf1c459cd4 100644 (file)
@@ -410,6 +410,21 @@ with ins (a, b, c) as
  mlparted4  | 1 |  30 |  39
 (5 rows)
 
+alter table mlparted add c text;
+create table mlparted5 (c text, a int not null, b int not null) partition by list (c);
+create table mlparted5a (a int not null, c text, b int not null);
+alter table mlparted5 attach partition mlparted5a for values in ('a');
+alter table mlparted attach partition mlparted5 for values from (1, 40) to (1, 50);
+alter table mlparted add constraint check_b check (a = 1 and b < 45);
+insert into mlparted values (1, 45, 'a');
+ERROR:  new row for relation "mlparted5a" violates check constraint "check_b"
+DETAIL:  Failing row contains (1, 45, a).
+create function mlparted5abrtrig_func() returns trigger as $$ begin new.c = 'b'; return new; end; $$ language plpgsql;
+create trigger mlparted5abrtrig before insert on mlparted5a for each row execute procedure mlparted5abrtrig_func();
+insert into mlparted5 (a, b, c) values (1, 40, 'a');
+ERROR:  new row for relation "mlparted5a" violates partition constraint
+DETAIL:  Failing row contains (b, 1, 40).
+drop table mlparted5;
 -- check that message shown after failure to find a partition shows the
 -- appropriate key description (or none) in various situations
 create table key_desc (a int, b int) partition by list ((a+0));
index caca81a70b6b793d104e4715229fecc81fede116..eab5c0334c5daee2893de46d00035f01e94f7551 100644 (file)
@@ -2368,8 +2368,8 @@ DETAIL:  Failing row contains (-1, invalid).
 DROP VIEW v1;
 DROP TABLE t1;
 -- check that an auto-updatable view on a partitioned table works correctly
-create table pt (a int, b int) partition by range (a, b);
-create table pt1 (b int not null, a int not null) partition by range (b);
+create table pt (a int, b int, v varchar) partition by range (a, b);
+create table pt1 (b int not null, v varchar, a int not null) partition by range (b);
 create table pt11 (like pt1);
 alter table pt11 drop a;
 alter table pt11 add a int;
@@ -2412,18 +2412,19 @@ select table_name, column_name, is_updatable
 ------------+-------------+--------------
  ptv        | a           | YES
  ptv        | b           | YES
-(2 rows)
+ ptv        | v           | YES
+(3 rows)
 
 insert into ptv values (1, 2);
 select tableoid::regclass, * from pt;
- tableoid | a | b 
-----------+---+---
- pt11     | 1 | 2
+ tableoid | a | b | v 
+----------+---+---+---
+ pt11     | 1 | 2 | 
 (1 row)
 
 create view ptv_wco as select * from pt where a = 0 with check option;
 insert into ptv_wco values (1, 2);
 ERROR:  new row violates check option for view "ptv_wco"
-DETAIL:  Failing row contains (1, 2).
+DETAIL:  Failing row contains (1, 2, null).
 drop view ptv, ptv_wco;
 drop table pt, pt1, pt11;
index 7666a7d6ca5934f4207877bf4273d3dcef82a0a8..6adf25da40e4edb2cf21a24e686c981890677ba2 100644 (file)
@@ -263,6 +263,18 @@ with ins (a, b, c) as
   (insert into mlparted (b, a) select s.a, 1 from generate_series(2, 39) s(a) returning tableoid::regclass, *)
   select a, b, min(c), max(c) from ins group by a, b order by 1;
 
+alter table mlparted add c text;
+create table mlparted5 (c text, a int not null, b int not null) partition by list (c);
+create table mlparted5a (a int not null, c text, b int not null);
+alter table mlparted5 attach partition mlparted5a for values in ('a');
+alter table mlparted attach partition mlparted5 for values from (1, 40) to (1, 50);
+alter table mlparted add constraint check_b check (a = 1 and b < 45);
+insert into mlparted values (1, 45, 'a');
+create function mlparted5abrtrig_func() returns trigger as $$ begin new.c = 'b'; return new; end; $$ language plpgsql;
+create trigger mlparted5abrtrig before insert on mlparted5a for each row execute procedure mlparted5abrtrig_func();
+insert into mlparted5 (a, b, c) values (1, 40, 'a');
+drop table mlparted5;
+
 -- check that message shown after failure to find a partition shows the
 -- appropriate key description (or none) in various situations
 create table key_desc (a int, b int) partition by list ((a+0));
index 6a9958d38b9b51d5df43efdb576175107943d7c0..2ede44c02b165446263c144e9d9778bd302e7c13 100644 (file)
@@ -1114,8 +1114,8 @@ DROP VIEW v1;
 DROP TABLE t1;
 
 -- check that an auto-updatable view on a partitioned table works correctly
-create table pt (a int, b int) partition by range (a, b);
-create table pt1 (b int not null, a int not null) partition by range (b);
+create table pt (a int, b int, v varchar) partition by range (a, b);
+create table pt1 (b int not null, v varchar, a int not null) partition by range (b);
 create table pt11 (like pt1);
 alter table pt11 drop a;
 alter table pt11 add a int;