On Wed, Jul 22, 2020 at 3:16 PM Amit Langote <amitlangot...@gmail.com> wrote: > On Mon, Jul 20, 2020 at 8:35 PM Amit Kapila <amit.kapil...@gmail.com> wrote: > > IIUC, here the problem is related to below part of code: > > ExecInsert(..) > > { > > /* Process RETURNING if present */ > > if (resultRelInfo->ri_projectReturning) > > result = ExecProcessReturning(resultRelInfo, slot, planSlot); > > .. > > } > > > > The reason is that planSlot is for foo1 and slot is for foo2 and when > > it tries to access tuple during ExecProcessReturning(), it results in > > an error. Is my understanding correct? > > Yes. Specifically, the problem exists if there are any non-target > relation attributes in RETURNING which are computed by referring to > planSlot, the plan's output tuple, which may be shaped differently > among result relations due to their tuple descriptors being different. > > > If so, then can't we ensure > > someway that planSlot also belongs to foo2 instead of skipping return > > processing in Insert and then later do more work to perform in Update. > > I did consider that option but failed to see a way to make it work. > > I am not sure if there is a way to make a copy of the plan's output > tuple (planSlot) that is compatible with the destination partition. > Simple conversion using execute_attr_map_slot() is okay when we know > the source and the target slots contain relation tuples, but plan's > output tuples will also have other junk attributes. Also, not all > destination partitions have an associated plan and hence a slot to > hold plan tuples.
Yeah, I think it might be possible to create planSlot to pass to ExecInsert() so that we can process RETURNING within that function, but even if so, that would be cumbersome not only because partitions can have different rowtypes but because they can have different junk columns as well, because e.g., subplan foreign partitions may have different row ID columns as junk columns. The proposed patch is simple, so I would vote for it. (Note: in case of a foreign partition, we call ExecForeignInsert() with the source partition’s planSlot in ExecInsert(), which is not correct, but that would sbe OK because it seems unlikely that the FDW would look at the planSlot for INSERT.) One thing I noticed is that the patch changes the existing behavior. Here is an example: create table range_parted (a text, b bigint) partition by range (a, b); create table part_a_1_a_10 partition of range_parted for values from ('a', 1) to ('a', 10); create table part_b_1_b_10 partition of range_parted for values from ('b', 1) to ('b', 10); create function trigfunc() returns trigger as $$ begin return null; end; $$ language plpgsql; create trigger trig before insert on part_b_1_b_10 for each row execute function trigfunc(); insert into range_parted values ('a', 1); In HEAD: postgres=# update range_parted r set a = 'b' from (values ('a', 1)) s(x, y) where s.x = r.a and s.y = r.b returning tableoid::regclass, r.*; tableoid | a | b ----------+---+--- (0 rows) UPDATE 0 But with the patch: postgres=# update range_parted r set a = 'b' from (values ('a', 1)) s(x, y) where s.x = r.a and s.y = r.b returning tableoid::regclass, r.*; tableoid | a | b ---------------+---+--- part_a_1_a_10 | b | 1 (1 row) UPDATE 1 This produces RETURNING, though INSERT on the destination partition was skipped by the trigger. Another thing is that the patch assumes that the tuple slot to pass to ExecInsert() would store the inserted tuple when doing that function, but that’s not always true, because in case of a foreign partition, the FDW may return a slot other than the passed-in slot when called from ExecForeignInsert(), in which case the passed-in slot would not store the inserted tuple anymore. To fix these, I modified the patch so that we 1) add to ExecInsert() an output parameter slot to store the inserted tuple, and 2) compute RETURNING based on the parameter. I also added a regression test case. Attached is an updated version of the patch. Sorry for the long delay. Best regards, Etsuro Fujita
v3-0001-Fix-a-bug-with-RETURNING-when-UPDATE-moves-tuple.patch
Description: Binary data