gpdb
gpdb copied to clipboard
6X: Fix assert on select ... from tbl returning ctid
- How to reproduce
- create table and trigger
gpadmin=# create table loc1 (f1 serial, f2 text);
gpadmin=# CREATE FUNCTION trig_row_before_insupdate() RETURNS TRIGGER AS $$
BEGIN
NEW.f2 := NEW.f2 || ' triggered !';
RETURN NEW;
END
$$ language plpgsql;
gpadmin=# CREATE TRIGGER trig_local_before BEFORE INSERT OR UPDATE ON loc1
FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
- insert a value, then assert pops
gpadmin=# INSERT INTO loc1(f2) VALUES ('test') RETURNING ctid;
ERROR: Unexpected internal error (execTuples.c:1559) (seg1 slice2 10.117.190.45:7001 pid=19255) (execTuples.c:1559)
DETAIL: FailedAssertion("!(((bool) (((const void*)(&(htup->t_self)) != ((void *)0)) && ((&(htup->t_self))->ip_posid != 0))))", File: "execTuples.c", Line: 1559)
HINT: Process 19255 will wait for gp_debug_linger=120 seconds before termination.
Note that its locks and other resources will not be released until then.
- root cause
the root cause is that if a table has trigger, the slot will be modified by trigger and be different from parentslot in
ExecInsert()
and then the ExecProcessReturning() will crash due to invalid parentslot.
so we fix this issue referring to the fdw handling in ExecInsert()
Co-authored-by: Amy Bai [email protected]
Here are some reminders before you submit the pull request
- [x] Add tests for the change
- [ ] Document changes
- [ ] Communicate in the mailing list if needed
- [x] Pass
make installcheck
- [x] Review a PR in return to support the community
the solution may be not perfect. Any suggestion is welcome. And the test case will be added later.
I have tried with the reproduce script on my 6x branch without this patch, but failed to reproduce: https://github.com/Aegeaner/gpdb/tree/gp2gp-build
$ psql postgres
psql (9.4.24)
Type "help" for help.
postgres=# \d loc1
Table "public.loc1"
Column | Type | Modifiers
--------+---------+---------------------------------------------------
f1 | integer | not null default nextval('loc1_f1_seq'::regclass)
f2 | text |
Triggers:
trig_local_before BEFORE INSERT OR UPDATE ON loc1 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate()
Distributed by: (f1)
postgres=# INSERT INTO loc1(f2) VALUES ('test') RETURNING ctid;
ctid
----------------
(4294967295,0)
(1 row)
INSERT 0 1
INSERT INTO loc1(f2) VALUES ('test') RETURNING ctid;
Actually, this issue can be reproduced on the latest 6X_STABLE branch.
Code change LGTM. Thanks. Several comments:
- the title is select xxx returning, it is a typo?
- I see this issue reproduce with UPDATE (I see the trigger is insert or update)
- can we test under AO|AOCO table?