Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0563a3a

Browse files
committed
Fix a bug in how we generate partition constraints.
Move the code for doing parent attnos to child attnos mapping for Varsin partition constraint expressions to a separate functionmap_partition_varattnos() and call it from the appropriate places.Doing it in get_qual_from_partbound(), as is now, would produce wrongresult in certain multi-level partitioning cases, because it onlyconsiders the current pair of parent-child relations. In certainmulti-level partitioning cases, attnums for the same key attribute(s)might differ between various levels causing the same attribute to benumbered differently in different instances of the Var correspondingto a given attribute.With this commit, in generate_partition_qual(), we first generate thethe whole partition constraint (considering all levels of partitioning)and then do the mapping, so that Vars in the final expression arenumbered according the leaf relation (to which it is supposed to apply).Amit Langote, reviewed by me.
1 parent0c2070c commit0563a3a

File tree

5 files changed

+110
-52
lines changed

5 files changed

+110
-52
lines changed

‎src/backend/catalog/partition.c

Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -852,10 +852,6 @@ get_qual_from_partbound(Relation rel, Relation parent, Node *bound)
852852
PartitionBoundSpec*spec= (PartitionBoundSpec*)bound;
853853
PartitionKeykey=RelationGetPartitionKey(parent);
854854
List*my_qual=NIL;
855-
TupleDescparent_tupdesc=RelationGetDescr(parent);
856-
AttrNumberparent_attno;
857-
AttrNumber*partition_attnos;
858-
boolfound_whole_row;
859855

860856
Assert(key!=NULL);
861857

@@ -876,38 +872,51 @@ get_qual_from_partbound(Relation rel, Relation parent, Node *bound)
876872
(int)key->strategy);
877873
}
878874

879-
/*
880-
* Translate vars in the generated expression to have correct attnos. Note
881-
* that the vars in my_qual bear attnos dictated by key which carries
882-
* physical attnos of the parent. We must allow for a case where physical
883-
* attnos of a partition can be different from the parent.
884-
*/
885-
partition_attnos= (AttrNumber*)
886-
palloc0(parent_tupdesc->natts*sizeof(AttrNumber));
887-
for (parent_attno=1;parent_attno <=parent_tupdesc->natts;
888-
parent_attno++)
875+
returnmy_qual;
876+
}
877+
878+
/*
879+
* map_partition_varattnos - maps varattno of any Vars in expr from the
880+
* parent attno to partition attno.
881+
*
882+
* We must allow for a case where physical attnos of a partition can be
883+
* different from the parent's.
884+
*/
885+
List*
886+
map_partition_varattnos(List*expr,Relationpartrel,Relationparent)
887+
{
888+
TupleDesctupdesc=RelationGetDescr(parent);
889+
AttrNumberattno;
890+
AttrNumber*part_attnos;
891+
boolfound_whole_row;
892+
893+
if (expr==NIL)
894+
returnNIL;
895+
896+
part_attnos= (AttrNumber*)palloc0(tupdesc->natts*sizeof(AttrNumber));
897+
for (attno=1;attno <=tupdesc->natts;attno++)
889898
{
890-
Form_pg_attributeattribute=parent_tupdesc->attrs[parent_attno-1];
899+
Form_pg_attributeattribute=tupdesc->attrs[attno-1];
891900
char*attname=NameStr(attribute->attname);
892-
AttrNumberpartition_attno;
901+
AttrNumberpart_attno;
893902

894903
if (attribute->attisdropped)
895904
continue;
896905

897-
partition_attno=get_attnum(RelationGetRelid(rel),attname);
898-
partition_attnos[parent_attno-1]=partition_attno;
906+
part_attno=get_attnum(RelationGetRelid(partrel),attname);
907+
part_attnos[attno-1]=part_attno;
899908
}
900909

901-
my_qual= (List*)map_variable_attnos((Node*)my_qual,
902-
1,0,
903-
partition_attnos,
904-
parent_tupdesc->natts,
905-
&found_whole_row);
906-
/*there can never be a whole-row reference here */
910+
expr= (List*)map_variable_attnos((Node*)expr,
911+
1,0,
912+
part_attnos,
913+
tupdesc->natts,
914+
&found_whole_row);
915+
/*There can never be a whole-row reference here */
907916
if (found_whole_row)
908917
elog(ERROR,"unexpected whole-row reference found in partition key");
909918

910-
returnmy_qual;
919+
returnexpr;
911920
}
912921

913922
/*
@@ -1496,27 +1505,15 @@ generate_partition_qual(Relation rel)
14961505
/* Guard against stack overflow due to overly deep partition tree */
14971506
check_stack_depth();
14981507

1508+
/* Quick copy */
1509+
if (rel->rd_partcheck!=NIL)
1510+
returncopyObject(rel->rd_partcheck);
1511+
14991512
/* Grab at least an AccessShareLock on the parent table */
15001513
parent=heap_open(get_partition_parent(RelationGetRelid(rel)),
15011514
AccessShareLock);
15021515

1503-
/* Quick copy */
1504-
if (rel->rd_partcheck)
1505-
{
1506-
if (parent->rd_rel->relispartition)
1507-
result=list_concat(generate_partition_qual(parent),
1508-
copyObject(rel->rd_partcheck));
1509-
else
1510-
result=copyObject(rel->rd_partcheck);
1511-
1512-
heap_close(parent,AccessShareLock);
1513-
returnresult;
1514-
}
1515-
15161516
/* Get pg_class.relpartbound */
1517-
if (!rel->rd_rel->relispartition)/* should not happen */
1518-
elog(ERROR,"relation \"%s\" has relispartition = false",
1519-
RelationGetRelationName(rel));
15201517
tuple=SearchSysCache1(RELOID,RelationGetRelid(rel));
15211518
if (!HeapTupleIsValid(tuple))
15221519
elog(ERROR,"cache lookup failed for relation %u",
@@ -1533,20 +1530,22 @@ generate_partition_qual(Relation rel)
15331530

15341531
my_qual=get_qual_from_partbound(rel,parent,bound);
15351532

1536-
/*If requested, add parent's quals to the list (if any) */
1533+
/*Add the parent's quals to the list (if any) */
15371534
if (parent->rd_rel->relispartition)
1538-
{
1539-
List*parent_check;
1540-
1541-
parent_check=generate_partition_qual(parent);
1542-
result=list_concat(parent_check,my_qual);
1543-
}
1535+
result=list_concat(generate_partition_qual(parent),my_qual);
15441536
else
15451537
result=my_qual;
15461538

1547-
/* Save a copy of my_qual in the relcache */
1539+
/*
1540+
* Change Vars to have partition's attnos instead of the parent's.
1541+
* We do this after we concatenate the parent's quals, because
1542+
* we want every Var in it to bear this relation's attnos.
1543+
*/
1544+
result=map_partition_varattnos(result,rel,parent);
1545+
1546+
/* Save a copy in the relcache */
15481547
oldcxt=MemoryContextSwitchTo(CacheMemoryContext);
1549-
rel->rd_partcheck=copyObject(my_qual);
1548+
rel->rd_partcheck=copyObject(result);
15501549
MemoryContextSwitchTo(oldcxt);
15511550

15521551
/* Keep the parent locked until commit */

‎src/backend/commands/tablecmds.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13429,6 +13429,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1342913429
Oidpart_relid=lfirst_oid(lc);
1343013430
Relationpart_rel;
1343113431
Expr*constr;
13432+
List*my_constr;
1343213433

1343313434
/* Lock already taken */
1343413435
if (part_relid!=RelationGetRelid(attachRel))
@@ -13451,8 +13452,10 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1345113452
tab=ATGetQueueEntry(wqueue,part_rel);
1345213453

1345313454
constr=linitial(partConstraint);
13454-
tab->partition_constraint=make_ands_implicit((Expr*)constr);
13455-
13455+
my_constr=make_ands_implicit((Expr*)constr);
13456+
tab->partition_constraint=map_partition_varattnos(my_constr,
13457+
part_rel,
13458+
rel);
1345613459
/* keep our lock until commit */
1345713460
if (part_rel!=attachRel)
1345813461
heap_close(part_rel,NoLock);

‎src/include/catalog/partition.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ extern bool partition_bounds_equal(PartitionKey key,
7777
externvoidcheck_new_partition_bound(char*relname,Relationparent,Node*bound);
7878
externOidget_partition_parent(Oidrelid);
7979
externList*get_qual_from_partbound(Relationrel,Relationparent,Node*bound);
80+
externList*map_partition_varattnos(List*expr,Relationpartrel,Relationparent);
8081
externList*RelationGetPartitionQual(Relationrel);
8182

8283
/* For tuple routing */

‎src/test/regress/expected/alter_table.out

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3339,3 +3339,33 @@ drop cascades to table part_2
33393339
drop cascades to table part_5
33403340
drop cascades to table part_5_a
33413341
drop cascades to table part_1
3342+
-- more tests for certain multi-level partitioning scenarios
3343+
create table p (a int, b int) partition by range (a, b);
3344+
create table p1 (b int, a int not null) partition by range (b);
3345+
create table p11 (like p1);
3346+
alter table p11 drop a;
3347+
alter table p11 add a int;
3348+
alter table p11 drop a;
3349+
alter table p11 add a int not null;
3350+
-- attnum for key attribute 'a' is different in p, p1, and p11
3351+
select attrelid::regclass, attname, attnum
3352+
from pg_attribute
3353+
where attname = 'a'
3354+
and (attrelid = 'p'::regclass
3355+
or attrelid = 'p1'::regclass
3356+
or attrelid = 'p11'::regclass);
3357+
attrelid | attname | attnum
3358+
----------+---------+--------
3359+
p | a | 1
3360+
p1 | a | 2
3361+
p11 | a | 4
3362+
(3 rows)
3363+
3364+
alter table p1 attach partition p11 for values from (2) to (5);
3365+
insert into p1 (a, b) values (2, 3);
3366+
-- check that partition validation scan correctly detects violating rows
3367+
alter table p attach partition p1 for values from (1, 2) to (1, 10);
3368+
ERROR: partition constraint is violated by some row
3369+
-- cleanup
3370+
drop table p, p1 cascade;
3371+
NOTICE: drop cascades to table p11

‎src/test/regress/sql/alter_table.sql

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,3 +2191,28 @@ ALTER TABLE list_parted2 ALTER COLUMN b TYPE text;
21912191

21922192
-- cleanup
21932193
DROPTABLE list_parted, list_parted2, range_parted CASCADE;
2194+
2195+
-- more tests for certain multi-level partitioning scenarios
2196+
createtablep (aint, bint) partition by range (a, b);
2197+
createtablep1 (bint, aintnot null) partition by range (b);
2198+
createtablep11 (like p1);
2199+
altertable p11 drop a;
2200+
altertable p11 add aint;
2201+
altertable p11 drop a;
2202+
altertable p11 add aintnot null;
2203+
-- attnum for key attribute 'a' is different in p, p1, and p11
2204+
select attrelid::regclass, attname, attnum
2205+
from pg_attribute
2206+
where attname='a'
2207+
and (attrelid='p'::regclass
2208+
or attrelid='p1'::regclass
2209+
or attrelid='p11'::regclass);
2210+
2211+
altertable p1 attach partition p11 forvaluesfrom (2) to (5);
2212+
2213+
insert into p1 (a, b)values (2,3);
2214+
-- check that partition validation scan correctly detects violating rows
2215+
altertable p attach partition p1 forvaluesfrom (1,2) to (1,10);
2216+
2217+
-- cleanup
2218+
droptable p, p1 cascade;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp