Skip to content

Commit 23cccb1

Browse files
committed
Fix for dropped columns in a partitioned table's default partition
We forgot to map column numbers to/from the default partition for various operations, leading to valid cases failing with spurious errors, such as ERROR: attribute N of type some_partition has been dropped It was also possible that the search for conflicting rows in the default partition when attaching another partition would fail to detect some. Secondarily, it was also possible that such a search should be skipped (because the constraint was implied) but wasn't. Fix all this by mapping column numbers when necessary. Reported by: Daniel Wilches Author: Amit Langote Discussion: https://postgr.es/m/[email protected]
1 parent 74b7cc8 commit 23cccb1

File tree

6 files changed

+70
-7
lines changed

6 files changed

+70
-7
lines changed

src/backend/commands/tablecmds.c

+7
Original file line numberDiff line numberDiff line change
@@ -15682,6 +15682,13 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1568215682
defaultrel = table_open(defaultPartOid, NoLock);
1568315683
defPartConstraint =
1568415684
get_proposed_default_constraint(partBoundConstraint);
15685+
/*
15686+
* Map the Vars in the constraint expression from rel's attnos to
15687+
* defaultrel's.
15688+
*/
15689+
defPartConstraint =
15690+
map_partition_varattnos(defPartConstraint,
15691+
1, defaultrel, rel, NULL);
1568515692
QueuePartitionConstraintValidation(wqueue, defaultrel,
1568615693
defPartConstraint, true);
1568715694

src/backend/partitioning/partbounds.c

+19-5
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,13 @@ check_default_partition_contents(Relation parent, Relation default_rel,
12371237
: get_qual_for_range(parent, new_spec, false);
12381238
def_part_constraints =
12391239
get_proposed_default_constraint(new_part_constraints);
1240+
/*
1241+
* Map the Vars in the constraint expression from parent's attnos to
1242+
* default_rel's.
1243+
*/
1244+
def_part_constraints =
1245+
map_partition_varattnos(def_part_constraints, 1, default_rel,
1246+
parent, NULL);
12401247

12411248
/*
12421249
* If the existing constraints on the default partition imply that it will
@@ -1265,7 +1272,6 @@ check_default_partition_contents(Relation parent, Relation default_rel,
12651272
{
12661273
Oid part_relid = lfirst_oid(lc);
12671274
Relation part_rel;
1268-
Expr *constr;
12691275
Expr *partition_constraint;
12701276
EState *estate;
12711277
ExprState *partqualstate = NULL;
@@ -1280,6 +1286,15 @@ check_default_partition_contents(Relation parent, Relation default_rel,
12801286
{
12811287
part_rel = table_open(part_relid, NoLock);
12821288

1289+
/*
1290+
* Map the Vars in the constraint expression from default_rel's
1291+
* the sub-partition's.
1292+
*/
1293+
partition_constraint = make_ands_explicit(def_part_constraints);
1294+
partition_constraint = (Expr *)
1295+
map_partition_varattnos((List *) partition_constraint, 1,
1296+
part_rel, default_rel, NULL);
1297+
12831298
/*
12841299
* If the partition constraints on default partition child imply
12851300
* that it will not contain any row that would belong to the new
@@ -1297,7 +1312,10 @@ check_default_partition_contents(Relation parent, Relation default_rel,
12971312
}
12981313
}
12991314
else
1315+
{
13001316
part_rel = default_rel;
1317+
partition_constraint = make_ands_explicit(def_part_constraints);
1318+
}
13011319

13021320
/*
13031321
* Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
@@ -1318,10 +1336,6 @@ check_default_partition_contents(Relation parent, Relation default_rel,
13181336
continue;
13191337
}
13201338

1321-
constr = linitial(def_part_constraints);
1322-
partition_constraint = (Expr *)
1323-
map_partition_varattnos((List *) constr,
1324-
1, part_rel, parent, NULL);
13251339
estate = CreateExecutorState();
13261340

13271341
/* Build expression execution states for partition check quals */

src/test/regress/expected/alter_table.out

+8-1
Original file line numberDiff line numberDiff line change
@@ -4008,7 +4008,8 @@ DROP USER regress_alter_table_user1;
40084008
-- default partition
40094009
create table defpart_attach_test (a int) partition by list (a);
40104010
create table defpart_attach_test1 partition of defpart_attach_test for values in (1);
4011-
create table defpart_attach_test_d (like defpart_attach_test);
4011+
create table defpart_attach_test_d (b int, a int);
4012+
alter table defpart_attach_test_d drop b;
40124013
insert into defpart_attach_test_d values (1), (2);
40134014
-- error because its constraint as the default partition would be violated
40144015
-- by the row containing 1
@@ -4019,6 +4020,12 @@ alter table defpart_attach_test_d add check (a > 1);
40194020
-- should be attached successfully and without needing to be scanned
40204021
alter table defpart_attach_test attach partition defpart_attach_test_d default;
40214022
INFO: partition constraint for table "defpart_attach_test_d" is implied by existing constraints
4023+
-- check that attaching a partition correctly reports any rows in the default
4024+
-- partition that should not be there for the new partition to be attached
4025+
-- successfully
4026+
create table defpart_attach_test_2 (like defpart_attach_test_d);
4027+
alter table defpart_attach_test attach partition defpart_attach_test_2 for values in (2);
4028+
ERROR: updated partition constraint for default partition would be violated by some row
40224029
drop table defpart_attach_test;
40234030
-- check combinations of temporary and permanent relations when attaching
40244031
-- partitions.

src/test/regress/expected/create_table.out

+14
Original file line numberDiff line numberDiff line change
@@ -1119,3 +1119,17 @@ select tableoid::regclass from volatile_partbound_test;
11191119
(1 row)
11201120

11211121
drop table volatile_partbound_test;
1122+
-- test the case where a check constraint on default partition allows
1123+
-- to avoid scanning it when adding a new partition
1124+
create table defcheck (a int, b int) partition by list (b);
1125+
create table defcheck_def (a int, c int, b int);
1126+
alter table defcheck_def drop c;
1127+
alter table defcheck attach partition defcheck_def default;
1128+
alter table defcheck_def add check (b <= 0 and b is not null);
1129+
create table defcheck_1 partition of defcheck for values in (1, null);
1130+
INFO: updated partition constraint for default partition "defcheck_def" is implied by existing constraints
1131+
-- test that complex default partition constraints are enforced correctly
1132+
insert into defcheck_def values (0, 0);
1133+
create table defcheck_0 partition of defcheck for values in (0);
1134+
ERROR: updated partition constraint for default partition "defcheck_def" would be violated by some row
1135+
drop table defcheck;

src/test/regress/sql/alter_table.sql

+8-1
Original file line numberDiff line numberDiff line change
@@ -2648,7 +2648,8 @@ DROP USER regress_alter_table_user1;
26482648
-- default partition
26492649
create table defpart_attach_test (a int) partition by list (a);
26502650
create table defpart_attach_test1 partition of defpart_attach_test for values in (1);
2651-
create table defpart_attach_test_d (like defpart_attach_test);
2651+
create table defpart_attach_test_d (b int, a int);
2652+
alter table defpart_attach_test_d drop b;
26522653
insert into defpart_attach_test_d values (1), (2);
26532654

26542655
-- error because its constraint as the default partition would be violated
@@ -2660,6 +2661,12 @@ alter table defpart_attach_test_d add check (a > 1);
26602661
-- should be attached successfully and without needing to be scanned
26612662
alter table defpart_attach_test attach partition defpart_attach_test_d default;
26622663

2664+
-- check that attaching a partition correctly reports any rows in the default
2665+
-- partition that should not be there for the new partition to be attached
2666+
-- successfully
2667+
create table defpart_attach_test_2 (like defpart_attach_test_d);
2668+
alter table defpart_attach_test attach partition defpart_attach_test_2 for values in (2);
2669+
26632670
drop table defpart_attach_test;
26642671

26652672
-- check combinations of temporary and permanent relations when attaching

src/test/regress/sql/create_table.sql

+14
Original file line numberDiff line numberDiff line change
@@ -856,3 +856,17 @@ create table volatile_partbound_test2 partition of volatile_partbound_test for v
856856
insert into volatile_partbound_test values (current_timestamp);
857857
select tableoid::regclass from volatile_partbound_test;
858858
drop table volatile_partbound_test;
859+
860+
-- test the case where a check constraint on default partition allows
861+
-- to avoid scanning it when adding a new partition
862+
create table defcheck (a int, b int) partition by list (b);
863+
create table defcheck_def (a int, c int, b int);
864+
alter table defcheck_def drop c;
865+
alter table defcheck attach partition defcheck_def default;
866+
alter table defcheck_def add check (b <= 0 and b is not null);
867+
create table defcheck_1 partition of defcheck for values in (1, null);
868+
869+
-- test that complex default partition constraints are enforced correctly
870+
insert into defcheck_def values (0, 0);
871+
create table defcheck_0 partition of defcheck for values in (0);
872+
drop table defcheck;

0 commit comments

Comments
 (0)