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

Commit610e8eb

Browse files
committed
Teach map_partition_varattnos to handle whole-row expressions.
Otherwise, partitioned tables with RETURNING expressions or subjectto a WITH CHECK OPTION do not work properly.Amit Langote, reviewed by Amit Khandekar and Etsuro Fujita. A fewcomment changes by me.Discussion:http://postgr.es/m/9a39df80-871e-6212-0684-f93c83be4097@lab.ntt.co.jp
1 parent5ff3d73 commit610e8eb

File tree

11 files changed

+157
-25
lines changed

11 files changed

+157
-25
lines changed

‎src/backend/catalog/partition.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -898,16 +898,20 @@ get_qual_from_partbound(Relation rel, Relation parent,
898898
* We must allow for cases where physical attnos of a partition can be
899899
* different from the parent's.
900900
*
901+
* If found_whole_row is not NULL, *found_whole_row returns whether a
902+
* whole-row variable was found in the input expression.
903+
*
901904
* Note: this will work on any node tree, so really the argument and result
902905
* should be declared "Node *". But a substantial majority of the callers
903906
* are working on Lists, so it's less messy to do the casts internally.
904907
*/
905908
List*
906909
map_partition_varattnos(List*expr,inttarget_varno,
907-
Relationpartrel,Relationparent)
910+
Relationpartrel,Relationparent,
911+
bool*found_whole_row)
908912
{
909913
AttrNumber*part_attnos;
910-
boolfound_whole_row;
914+
boolmy_found_whole_row;
911915

912916
if (expr==NIL)
913917
returnNIL;
@@ -919,10 +923,10 @@ map_partition_varattnos(List *expr, int target_varno,
919923
target_varno,0,
920924
part_attnos,
921925
RelationGetDescr(parent)->natts,
922-
&found_whole_row);
923-
/* There can never be a whole-row reference here */
926+
RelationGetForm(partrel)->reltype,
927+
&my_found_whole_row);
924928
if (found_whole_row)
925-
elog(ERROR,"unexpected whole-row reference found in partition key");
929+
*found_whole_row=my_found_whole_row;
926930

927931
returnexpr;
928932
}
@@ -1783,6 +1787,7 @@ generate_partition_qual(Relation rel)
17831787
List*my_qual=NIL,
17841788
*result=NIL;
17851789
Relationparent;
1790+
boolfound_whole_row;
17861791

17871792
/* Guard against stack overflow due to overly deep partition tree */
17881793
check_stack_depth();
@@ -1825,7 +1830,11 @@ generate_partition_qual(Relation rel)
18251830
* in it to bear this relation's attnos. It's safe to assume varno = 1
18261831
* here.
18271832
*/
1828-
result=map_partition_varattnos(result,1,rel,parent);
1833+
result=map_partition_varattnos(result,1,rel,parent,
1834+
&found_whole_row);
1835+
/* There can never be a whole-row reference here */
1836+
if (found_whole_row)
1837+
elog(ERROR,"unexpected whole-row reference found in partition key");
18291838

18301839
/* Save a copy in the relcache */
18311840
oldcxt=MemoryContextSwitchTo(CacheMemoryContext);

‎src/backend/commands/tablecmds.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,7 +1989,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
19891989
expr=map_variable_attnos(stringToNode(check[i].ccbin),
19901990
1,0,
19911991
newattno,tupleDesc->natts,
1992-
&found_whole_row);
1992+
InvalidOid,&found_whole_row);
19931993

19941994
/*
19951995
* For the moment we have to reject whole-row variables. We
@@ -8874,7 +8874,7 @@ ATPrepAlterColumnType(List **wqueue,
88748874
map_variable_attnos(def->cooked_default,
88758875
1,0,
88768876
attmap,RelationGetDescr(rel)->natts,
8877-
&found_whole_row);
8877+
InvalidOid,&found_whole_row);
88788878
if (found_whole_row)
88798879
ereport(ERROR,
88808880
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -13713,6 +13713,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1371313713
Oidpart_relid=lfirst_oid(lc);
1371413714
Relationpart_rel;
1371513715
Expr*constr;
13716+
boolfound_whole_row;
1371613717

1371713718
/* Lock already taken */
1371813719
if (part_relid!=RelationGetRelid(attachRel))
@@ -13738,7 +13739,12 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1373813739
constr=linitial(partConstraint);
1373913740
tab->partition_constraint= (Expr*)
1374013741
map_partition_varattnos((List*)constr,1,
13741-
part_rel,rel);
13742+
part_rel,rel,
13743+
&found_whole_row);
13744+
/* There can never be a whole-row reference here */
13745+
if (found_whole_row)
13746+
elog(ERROR,"unexpected whole-row reference found in partition key");
13747+
1374213748
/* keep our lock until commit */
1374313749
if (part_rel!=attachRel)
1374413750
heap_close(part_rel,NoLock);

‎src/backend/executor/nodeModifyTable.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1996,7 +1996,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
19961996
/* varno = node->nominalRelation */
19971997
mapped_wcoList=map_partition_varattnos(wcoList,
19981998
node->nominalRelation,
1999-
partrel,rel);
1999+
partrel,rel,NULL);
20002000
foreach(ll,mapped_wcoList)
20012001
{
20022002
WithCheckOption*wco=castNode(WithCheckOption,lfirst(ll));
@@ -2069,7 +2069,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
20692069
/* varno = node->nominalRelation */
20702070
rlist=map_partition_varattnos(returningList,
20712071
node->nominalRelation,
2072-
partrel,rel);
2072+
partrel,rel,NULL);
20732073
resultRelInfo->ri_projectReturning=
20742074
ExecBuildProjectionInfo(rlist,econtext,slot,&mtstate->ps,
20752075
resultRelInfo->ri_RelationDesc->rd_att);

‎src/backend/parser/parse_utilcmd.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
11071107
ccbin_node=map_variable_attnos(stringToNode(ccbin),
11081108
1,0,
11091109
attmap,tupleDesc->natts,
1110-
&found_whole_row);
1110+
InvalidOid,&found_whole_row);
11111111

11121112
/*
11131113
* We reject whole-row variables because the whole point of LIKE
@@ -1463,7 +1463,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
14631463
indexkey=map_variable_attnos(indexkey,
14641464
1,0,
14651465
attmap,attmap_length,
1466-
&found_whole_row);
1466+
InvalidOid,&found_whole_row);
14671467

14681468
/* As in transformTableLikeClause, reject whole-row variables */
14691469
if (found_whole_row)
@@ -1539,7 +1539,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
15391539
pred_tree=map_variable_attnos(pred_tree,
15401540
1,0,
15411541
attmap,attmap_length,
1542-
&found_whole_row);
1542+
InvalidOid,&found_whole_row);
15431543

15441544
/* As in transformTableLikeClause, reject whole-row variables */
15451545
if (found_whole_row)

‎src/backend/rewrite/rewriteManip.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,14 +1203,12 @@ replace_rte_variables_mutator(Node *node,
12031203
* appear in the expression.
12041204
*
12051205
* If the expression tree contains a whole-row Var for the target RTE,
1206-
* the Var is not changed but *found_whole_row is returned as TRUE.
1207-
* For most callers this is an error condition, but we leave it to the caller
1208-
* to report the error so that useful context can be provided. (In some
1209-
* usages it would be appropriate to modify the Var's vartype and insert a
1210-
* ConvertRowtypeExpr node to map back to the original vartype. We might
1211-
* someday extend this function's API to support that. For now, the only
1212-
* concession to that future need is that this function is a tree mutator
1213-
* not just a walker.)
1206+
* *found_whole_row is returned as TRUE. In addition, if to_rowtype is
1207+
* not InvalidOid, we modify the Var's vartype and insert a ConvertRowTypeExpr
1208+
* to map back to the orignal rowtype. Callers that don't provide to_rowtype
1209+
* should report an error if *found_row_type is true; we don't do that here
1210+
* because we don't know exactly what wording for the error message would
1211+
* be most appropriate. The caller will be aware of the context.
12141212
*
12151213
* This could be built using replace_rte_variables and a callback function,
12161214
* but since we don't ever need to insert sublinks, replace_rte_variables is
@@ -1223,6 +1221,8 @@ typedef struct
12231221
intsublevels_up;/* (current) nesting depth */
12241222
constAttrNumber*attno_map;/* map array for user attnos */
12251223
intmap_length;/* number of entries in attno_map[] */
1224+
/* Target type when converting whole-row vars */
1225+
Oidto_rowtype;
12261226
bool*found_whole_row;/* output flag */
12271227
}map_variable_attnos_context;
12281228

@@ -1257,6 +1257,34 @@ map_variable_attnos_mutator(Node *node,
12571257
{
12581258
/* whole-row variable, warn caller */
12591259
*(context->found_whole_row)= true;
1260+
1261+
/* If the callers expects us to convert the same, do so. */
1262+
if (OidIsValid(context->to_rowtype))
1263+
{
1264+
/* No support for RECORDOID. */
1265+
Assert(var->vartype!=RECORDOID);
1266+
1267+
/* Don't convert unless necessary. */
1268+
if (context->to_rowtype!=var->vartype)
1269+
{
1270+
ConvertRowtypeExpr*r;
1271+
1272+
/* Var itself is converted to the requested type. */
1273+
newvar->vartype=context->to_rowtype;
1274+
1275+
/*
1276+
* And a conversion node on top to convert back to the
1277+
* original type.
1278+
*/
1279+
r=makeNode(ConvertRowtypeExpr);
1280+
r->arg= (Expr*)newvar;
1281+
r->resulttype=var->vartype;
1282+
r->convertformat=COERCE_IMPLICIT_CAST;
1283+
r->location=-1;
1284+
1285+
return (Node*)r;
1286+
}
1287+
}
12601288
}
12611289
return (Node*)newvar;
12621290
}
@@ -1283,14 +1311,15 @@ Node *
12831311
map_variable_attnos(Node*node,
12841312
inttarget_varno,intsublevels_up,
12851313
constAttrNumber*attno_map,intmap_length,
1286-
bool*found_whole_row)
1314+
Oidto_rowtype,bool*found_whole_row)
12871315
{
12881316
map_variable_attnos_contextcontext;
12891317

12901318
context.target_varno=target_varno;
12911319
context.sublevels_up=sublevels_up;
12921320
context.attno_map=attno_map;
12931321
context.map_length=map_length;
1322+
context.to_rowtype=to_rowtype;
12941323
context.found_whole_row=found_whole_row;
12951324

12961325
*found_whole_row= false;

‎src/include/catalog/partition.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ extern Oidget_partition_parent(Oid relid);
8080
externList*get_qual_from_partbound(Relationrel,Relationparent,
8181
PartitionBoundSpec*spec);
8282
externList*map_partition_varattnos(List*expr,inttarget_varno,
83-
Relationpartrel,Relationparent);
83+
Relationpartrel,Relationparent,
84+
bool*found_whole_row);
8485
externList*RelationGetPartitionQual(Relationrel);
8586
externExpr*get_partition_qual_relid(Oidrelid);
8687

‎src/include/rewrite/rewriteManip.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ extern Node *replace_rte_variables_mutator(Node *node,
7272
externNode*map_variable_attnos(Node*node,
7373
inttarget_varno,intsublevels_up,
7474
constAttrNumber*attno_map,intmap_length,
75-
bool*found_whole_row);
75+
Oidto_rowtype,bool*found_whole_row);
7676

7777
externNode*ReplaceVarsFromTargetList(Node*node,
7878
inttarget_varno,intsublevels_up,

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,3 +659,24 @@ select tableoid::regclass, * from mcrparted order by a, b;
659659
(11 rows)
660660

661661
drop table mcrparted;
662+
-- check that wholerow vars in the RETURNING list work with partitioned tables
663+
create table returningwrtest (a int) partition by list (a);
664+
create table returningwrtest1 partition of returningwrtest for values in (1);
665+
insert into returningwrtest values (1) returning returningwrtest;
666+
returningwrtest
667+
-----------------
668+
(1)
669+
(1 row)
670+
671+
-- check also that the wholerow vars in RETURNING list are converted as needed
672+
alter table returningwrtest add b text;
673+
create table returningwrtest2 (b text, c int, a int);
674+
alter table returningwrtest2 drop c;
675+
alter table returningwrtest attach partition returningwrtest2 for values in (2);
676+
insert into returningwrtest values (2, 'foo') returning returningwrtest;
677+
returningwrtest
678+
-----------------
679+
(2,foo)
680+
(1 row)
681+
682+
drop table returningwrtest;

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2428,3 +2428,29 @@ ERROR: new row violates check option for view "ptv_wco"
24282428
DETAIL: Failing row contains (1, 2, null).
24292429
drop view ptv, ptv_wco;
24302430
drop table pt, pt1, pt11;
2431+
-- check that wholerow vars appearing in WITH CHECK OPTION constraint expressions
2432+
-- work fine with partitioned tables
2433+
create table wcowrtest (a int) partition by list (a);
2434+
create table wcowrtest1 partition of wcowrtest for values in (1);
2435+
create view wcowrtest_v as select * from wcowrtest where wcowrtest = '(2)'::wcowrtest with check option;
2436+
insert into wcowrtest_v values (1);
2437+
ERROR: new row violates check option for view "wcowrtest_v"
2438+
DETAIL: Failing row contains (1).
2439+
alter table wcowrtest add b text;
2440+
create table wcowrtest2 (b text, c int, a int);
2441+
alter table wcowrtest2 drop c;
2442+
alter table wcowrtest attach partition wcowrtest2 for values in (2);
2443+
create table sometable (a int, b text);
2444+
insert into sometable values (1, 'a'), (2, 'b');
2445+
create view wcowrtest_v2 as
2446+
select *
2447+
from wcowrtest r
2448+
where r in (select s from sometable s where r.a = s.a)
2449+
with check option;
2450+
-- WITH CHECK qual will be processed with wcowrtest2's
2451+
-- rowtype after tuple-routing
2452+
insert into wcowrtest_v2 values (2, 'no such row in sometable');
2453+
ERROR: new row violates check option for view "wcowrtest_v2"
2454+
DETAIL: Failing row contains (2, no such row in sometable).
2455+
drop view wcowrtest_v, wcowrtest_v2;
2456+
drop table wcowrtest, sometable;

‎src/test/regress/sql/insert.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,3 +399,16 @@ insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),
399399
('commons',0), ('d',-10), ('e',0);
400400
select tableoid::regclass,*from mcrpartedorder by a, b;
401401
droptable mcrparted;
402+
403+
-- check that wholerow vars in the RETURNING list work with partitioned tables
404+
createtablereturningwrtest (aint) partition by list (a);
405+
createtablereturningwrtest1 partition of returningwrtest forvaluesin (1);
406+
insert into returningwrtestvalues (1) returning returningwrtest;
407+
408+
-- check also that the wholerow vars in RETURNING list are converted as needed
409+
altertable returningwrtest add btext;
410+
createtablereturningwrtest2 (btext, cint, aint);
411+
altertable returningwrtest2 drop c;
412+
altertable returningwrtest attach partition returningwrtest2 forvaluesin (2);
413+
insert into returningwrtestvalues (2,'foo') returning returningwrtest;
414+
droptable returningwrtest;

‎src/test/regress/sql/updatable_views.sql

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,3 +1141,30 @@ create view ptv_wco as select * from pt where a = 0 with check option;
11411141
insert into ptv_wcovalues (1,2);
11421142
dropview ptv, ptv_wco;
11431143
droptable pt, pt1, pt11;
1144+
1145+
-- check that wholerow vars appearing in WITH CHECK OPTION constraint expressions
1146+
-- work fine with partitioned tables
1147+
createtablewcowrtest (aint) partition by list (a);
1148+
createtablewcowrtest1 partition of wcowrtest forvaluesin (1);
1149+
createviewwcowrtest_vasselect*from wcowrtestwhere wcowrtest='(2)'::wcowrtest withcheck option;
1150+
insert into wcowrtest_vvalues (1);
1151+
1152+
altertable wcowrtest add btext;
1153+
createtablewcowrtest2 (btext, cint, aint);
1154+
altertable wcowrtest2 drop c;
1155+
altertable wcowrtest attach partition wcowrtest2 forvaluesin (2);
1156+
1157+
createtablesometable (aint, btext);
1158+
insert into sometablevalues (1,'a'), (2,'b');
1159+
createviewwcowrtest_v2as
1160+
select*
1161+
from wcowrtest r
1162+
where rin (select sfrom sometable swherer.a=s.a)
1163+
withcheck option;
1164+
1165+
-- WITH CHECK qual will be processed with wcowrtest2's
1166+
-- rowtype after tuple-routing
1167+
insert into wcowrtest_v2values (2,'no such row in sometable');
1168+
1169+
dropview wcowrtest_v, wcowrtest_v2;
1170+
droptable wcowrtest, sometable;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp