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

Commit158b7bc

Browse files
committed
Ignore whole-rows in INSERT/CONFLICT with partitioned tables
We had an Assert() preventing whole-row expressions from being used inthe SET clause of INSERT ON CONFLICT, but it seems unnecessary, givensome tests, so remove it. Add a new test to exercise the case.Still at ExecInitPartitionInfo, we used map_partition_varattnos (whichconstructs an attribute map, then calls map_variable_attnos) usingthe same two relations many times in different expressions and withdifferent parameters. Constructing the map over and over is a waste.To avoid this repeated work, construct the map once, and usemap_variable_attnos() directly instead.Author: Amit Langote, per comments by me (Álvaro)Discussion:https://postgr.es/m/20180326142016.m4st5e34chrzrknk@alvherre.pgsql
1 parent3a2d636 commit158b7bc

File tree

3 files changed

+125
-30
lines changed

3 files changed

+125
-30
lines changed

‎src/backend/executor/execPartition.c

Lines changed: 91 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include"nodes/makefuncs.h"
2525
#include"partitioning/partbounds.h"
2626
#include"partitioning/partprune.h"
27+
#include"rewrite/rewriteManip.h"
2728
#include"utils/lsyscache.h"
2829
#include"utils/partcache.h"
2930
#include"utils/rel.h"
@@ -307,8 +308,12 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
307308
ModifyTable*node= (ModifyTable*)mtstate->ps.plan;
308309
Relationrootrel=resultRelInfo->ri_RelationDesc,
309310
partrel;
311+
RelationfirstResultRel=mtstate->resultRelInfo[0].ri_RelationDesc;
310312
ResultRelInfo*leaf_part_rri;
311313
MemoryContextoldContext;
314+
AttrNumber*part_attnos=NULL;
315+
boolfound_whole_row;
316+
boolequalTupdescs;
312317

313318
/*
314319
* We locked all the partitions in ExecSetupPartitionTupleRouting
@@ -356,6 +361,10 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
356361
(node!=NULL&&
357362
node->onConflictAction!=ONCONFLICT_NONE));
358363

364+
/* if tuple descs are identical, we don't need to map the attrs */
365+
equalTupdescs=equalTupleDescs(RelationGetDescr(partrel),
366+
RelationGetDescr(firstResultRel));
367+
359368
/*
360369
* Build WITH CHECK OPTION constraints for the partition. Note that we
361370
* didn't build the withCheckOptionList for partitions within the planner,
@@ -369,7 +378,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
369378
List*wcoExprs=NIL;
370379
ListCell*ll;
371380
intfirstVarno=mtstate->resultRelInfo[0].ri_RangeTableIndex;
372-
RelationfirstResultRel=mtstate->resultRelInfo[0].ri_RelationDesc;
373381

374382
/*
375383
* In the case of INSERT on a partitioned table, there is only one
@@ -397,8 +405,22 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
397405
/*
398406
* Convert Vars in it to contain this partition's attribute numbers.
399407
*/
400-
wcoList=map_partition_varattnos(wcoList,firstVarno,
401-
partrel,firstResultRel,NULL);
408+
if (!equalTupdescs)
409+
{
410+
part_attnos=
411+
convert_tuples_by_name_map(RelationGetDescr(partrel),
412+
RelationGetDescr(firstResultRel),
413+
gettext_noop("could not convert row type"));
414+
wcoList= (List*)
415+
map_variable_attnos((Node*)wcoList,
416+
firstVarno,0,
417+
part_attnos,
418+
RelationGetDescr(firstResultRel)->natts,
419+
RelationGetForm(partrel)->reltype,
420+
&found_whole_row);
421+
/* We ignore the value of found_whole_row. */
422+
}
423+
402424
foreach(ll,wcoList)
403425
{
404426
WithCheckOption*wco=castNode(WithCheckOption,lfirst(ll));
@@ -425,7 +447,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
425447
ExprContext*econtext;
426448
List*returningList;
427449
intfirstVarno=mtstate->resultRelInfo[0].ri_RangeTableIndex;
428-
RelationfirstResultRel=mtstate->resultRelInfo[0].ri_RelationDesc;
429450

430451
/* See the comment above for WCO lists. */
431452
Assert((node->operation==CMD_INSERT&&
@@ -443,12 +464,26 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
443464
*/
444465
returningList=linitial(node->returningLists);
445466

446-
/*
447-
* Convert Vars in it to contain this partition's attribute numbers.
448-
*/
449-
returningList=map_partition_varattnos(returningList,firstVarno,
450-
partrel,firstResultRel,
451-
NULL);
467+
if (!equalTupdescs)
468+
{
469+
/*
470+
* Convert Vars in it to contain this partition's attribute numbers.
471+
*/
472+
if (part_attnos==NULL)
473+
part_attnos=
474+
convert_tuples_by_name_map(RelationGetDescr(partrel),
475+
RelationGetDescr(firstResultRel),
476+
gettext_noop("could not convert row type"));
477+
returningList= (List*)
478+
map_variable_attnos((Node*)returningList,
479+
firstVarno,0,
480+
part_attnos,
481+
RelationGetDescr(firstResultRel)->natts,
482+
RelationGetForm(partrel)->reltype,
483+
&found_whole_row);
484+
/* We ignore the value of found_whole_row. */
485+
}
486+
452487
leaf_part_rri->ri_returningList=returningList;
453488

454489
/*
@@ -473,7 +508,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
473508
{
474509
TupleConversionMap*map=proute->parent_child_tupconv_maps[partidx];
475510
intfirstVarno=mtstate->resultRelInfo[0].ri_RangeTableIndex;
476-
RelationfirstResultRel=mtstate->resultRelInfo[0].ri_RelationDesc;
477511
TupleDescpartrelDesc=RelationGetDescr(partrel);
478512
ExprContext*econtext=mtstate->ps.ps_ExprContext;
479513
ListCell*lc;
@@ -549,17 +583,33 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
549583
* target relation (firstVarno).
550584
*/
551585
onconflset= (List*)copyObject((Node*)node->onConflictSet);
552-
onconflset=
553-
map_partition_varattnos(onconflset,INNER_VAR,partrel,
554-
firstResultRel,&found_whole_row);
555-
Assert(!found_whole_row);
556-
onconflset=
557-
map_partition_varattnos(onconflset,firstVarno,partrel,
558-
firstResultRel,&found_whole_row);
559-
Assert(!found_whole_row);
560-
561-
/* Finally, adjust this tlist to match the partition. */
562-
onconflset=adjust_partition_tlist(onconflset,map);
586+
if (!equalTupdescs)
587+
{
588+
if (part_attnos==NULL)
589+
part_attnos=
590+
convert_tuples_by_name_map(RelationGetDescr(partrel),
591+
RelationGetDescr(firstResultRel),
592+
gettext_noop("could not convert row type"));
593+
onconflset= (List*)
594+
map_variable_attnos((Node*)onconflset,
595+
INNER_VAR,0,
596+
part_attnos,
597+
RelationGetDescr(firstResultRel)->natts,
598+
RelationGetForm(partrel)->reltype,
599+
&found_whole_row);
600+
/* We ignore the value of found_whole_row. */
601+
onconflset= (List*)
602+
map_variable_attnos((Node*)onconflset,
603+
firstVarno,0,
604+
part_attnos,
605+
RelationGetDescr(firstResultRel)->natts,
606+
RelationGetForm(partrel)->reltype,
607+
&found_whole_row);
608+
/* We ignore the value of found_whole_row. */
609+
610+
/* Finally, adjust this tlist to match the partition. */
611+
onconflset=adjust_partition_tlist(onconflset,map);
612+
}
563613

564614
/*
565615
* Build UPDATE SET's projection info. The user of this
@@ -587,14 +637,25 @@ ExecInitPartitionInfo(ModifyTableState *mtstate,
587637
List*clause;
588638

589639
clause=copyObject((List*)node->onConflictWhere);
590-
clause=map_partition_varattnos(clause,INNER_VAR,
591-
partrel,firstResultRel,
592-
&found_whole_row);
593-
Assert(!found_whole_row);
594-
clause=map_partition_varattnos(clause,firstVarno,
595-
partrel,firstResultRel,
596-
&found_whole_row);
597-
Assert(!found_whole_row);
640+
if (!equalTupdescs)
641+
{
642+
clause= (List*)
643+
map_variable_attnos((Node*)clause,
644+
INNER_VAR,0,
645+
part_attnos,
646+
RelationGetDescr(firstResultRel)->natts,
647+
RelationGetForm(partrel)->reltype,
648+
&found_whole_row);
649+
/* We ignore the value of found_whole_row. */
650+
clause= (List*)
651+
map_variable_attnos((Node*)clause,
652+
firstVarno,0,
653+
part_attnos,
654+
RelationGetDescr(firstResultRel)->natts,
655+
RelationGetForm(partrel)->reltype,
656+
&found_whole_row);
657+
/* We ignore the value of found_whole_row. */
658+
}
598659
leaf_part_rri->ri_onConflict->oc_WhereClause=
599660
ExecInitQual((List*)clause,&mtstate->ps);
600661
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,4 +884,20 @@ insert into parted_conflict values (40, 'forty');
884884
insert into parted_conflict_1 values (40, 'cuarenta')
885885
on conflict (a) do update set b = excluded.b;
886886
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
887+
-- test whole-row Vars in ON CONFLICT expressions
888+
create unique index on parted_conflict (a, b);
889+
alter table parted_conflict add c int;
890+
truncate parted_conflict;
891+
insert into parted_conflict values (50, 'cincuenta', 1);
892+
insert into parted_conflict values (50, 'cincuenta', 2)
893+
on conflict (a, b) do update set (a, b, c) = row(excluded.*)
894+
where parted_conflict = (50, text 'cincuenta', 1) and
895+
excluded = (50, text 'cincuenta', 2);
896+
-- should see (50, 'cincuenta', 2)
897+
select * from parted_conflict order by a;
898+
a | b | c
899+
----+-----------+---
900+
50 | cincuenta | 2
901+
(1 row)
902+
887903
drop table parted_conflict;

‎src/test/regress/sql/insert_conflict.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,3 +559,21 @@ insert into parted_conflict values (40, 'forty');
559559
insert into parted_conflict_1values (40,'cuarenta')
560560
on conflict (a) doupdateset b=excluded.b;
561561
droptable parted_conflict;
562+
563+
-- test whole-row Vars in ON CONFLICT expressions
564+
createtableparted_conflict (aint, btext, cint) partition by range (a);
565+
createtableparted_conflict_1 (drptext, cint, aint, btext);
566+
altertable parted_conflict_1 drop column drp;
567+
createunique indexon parted_conflict (a, b);
568+
altertable parted_conflict attach partition parted_conflict_1 forvaluesfrom (0) to (1000);
569+
truncate parted_conflict;
570+
insert into parted_conflictvalues (50,'cincuenta',1);
571+
insert into parted_conflictvalues (50,'cincuenta',2)
572+
on conflict (a, b) doupdateset (a, b, c)= row(excluded.*)
573+
where parted_conflict= (50,text'cincuenta',1)and
574+
excluded= (50,text'cincuenta',2);
575+
576+
-- should see (50, 'cincuenta', 2)
577+
select*from parted_conflictorder by a;
578+
579+
droptable parted_conflict;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp