mirror of
https://github.com/postgres/postgres.git
synced 2026-07-15 20:52:53 -04:00
Forbid FOR PORTION OF on views with INSTEAD OF triggers
Previously, an attempt to use these features together caused a crash.
Oversight of commit 8e72d914c5.
Tests are added also to show that the check for this should be in the
rewriter, not the parser, as an earlier patch version suggested.
Author: Aleksander Alekseev <aleksander@tigerdata.com>
Author: Paul A. Jungwirth <pj@illuminatedcomputing.com>
Discussion: https://www.postgresql.org/message-id/flat/CAJ7c6TME%2Bix6VRf-2TPnVTsj8qn_hy6sYAOmMhZEivwsu2wS6g%40mail.gmail.com
This commit is contained in:
parent
3334b0d9f2
commit
5b5e99047a
3 changed files with 152 additions and 0 deletions
|
|
@ -4171,6 +4171,14 @@ RewriteQuery(Query *parsetree, List *rewrite_events, int orig_rt_length,
|
|||
*/
|
||||
rt_entry_relation = relation_open(rt_entry->relid, NoLock);
|
||||
|
||||
/* We don't support FOR PORTION OF on views with INSTEAD OF triggers. */
|
||||
if (parsetree->forPortionOf &&
|
||||
rt_entry_relation->rd_rel->relkind == RELKIND_VIEW &&
|
||||
view_has_instead_trigger(rt_entry_relation, event, NIL))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("views with INSTEAD OF triggers do not support FOR PORTION OF")));
|
||||
|
||||
/*
|
||||
* Rewrite the targetlist as needed for the command type.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4165,3 +4165,74 @@ select * from base_tab order by a;
|
|||
|
||||
drop view base_tab_view;
|
||||
drop table base_tab;
|
||||
-- FOR PORTION OF is not supported on views with INSTEAD OF triggers
|
||||
create view uv_fpo_instead_view as select id, valid_at, b from uv_fpo_tab;
|
||||
create function uv_fpo_instead_trig() returns trigger language plpgsql as
|
||||
$$ begin return null; end $$;
|
||||
create trigger uv_fpo_instead_upd_trig
|
||||
instead of update on uv_fpo_instead_view
|
||||
for each row execute function uv_fpo_instead_trig();
|
||||
create trigger uv_fpo_instead_del_trig
|
||||
instead of delete on uv_fpo_instead_view
|
||||
for each row execute function uv_fpo_instead_trig();
|
||||
update uv_fpo_instead_view
|
||||
for portion of valid_at from '2015-01-01' to '2020-01-01'
|
||||
set b = 99 where id = '[1,1]'; -- error
|
||||
ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
|
||||
delete from uv_fpo_instead_view
|
||||
for portion of valid_at from '2017-01-01' to '2022-01-01'
|
||||
where id = '[1,1]'; -- error
|
||||
ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
|
||||
-- The check does not depend on which rows match, so it errors even when
|
||||
-- no rows do.
|
||||
update uv_fpo_instead_view
|
||||
for portion of valid_at from '2015-01-01' to '2020-01-01'
|
||||
set b = 99 where id = '[9,9]'; -- error, even with no matching rows
|
||||
ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
|
||||
delete from uv_fpo_instead_view
|
||||
for portion of valid_at from '2017-01-01' to '2022-01-01'
|
||||
where id = '[9,9]'; -- error, even with no matching rows
|
||||
ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
|
||||
drop view uv_fpo_instead_view;
|
||||
drop function uv_fpo_instead_trig();
|
||||
-- Forbid INSTEAD OF triggers with FOR PORTION OF even if the FOR PORTION OF
|
||||
-- statement is parsed before the trigger exists.
|
||||
-- This can happen in at least a couple ways: a rewrite rule or a BEGIN ATOMIC function.
|
||||
create function uv_fpo_instead_trig() returns trigger language plpgsql as
|
||||
$$ begin return new; end $$;
|
||||
-- via a rewrite rule
|
||||
create table uv_fpo_rule_tab (id int4range, valid_at tsrange, b float);
|
||||
insert into uv_fpo_rule_tab values ('[1,1]', '[2000-01-01, 2030-01-01)', 0);
|
||||
create view uv_fpo_rule_view as select id, valid_at, b from uv_fpo_rule_tab;
|
||||
create rule uv_fpo_rule as on insert to uv_fpo_rule_tab do also
|
||||
update uv_fpo_rule_view
|
||||
for portion of valid_at from '2010-01-01' to '2020-01-01'
|
||||
set b = 99 where id = '[1,1]';
|
||||
create trigger uv_fpo_rule_instead
|
||||
instead of update on uv_fpo_rule_view
|
||||
for each row execute function uv_fpo_instead_trig();
|
||||
-- Would crash if we checked at parse-time:
|
||||
insert into uv_fpo_rule_tab values ('[2,2]', '[2000-01-01,2030-01-01)', 0);
|
||||
ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
|
||||
drop table uv_fpo_rule_tab cascade;
|
||||
NOTICE: drop cascades to view uv_fpo_rule_view
|
||||
-- via a BEGIN ATOMIC function body
|
||||
create table uv_fpo_atomic_tab (id int4range, valid_at tsrange, b float);
|
||||
insert into uv_fpo_atomic_tab values ('[1,1]', '[2000-01-01, 2030-01-01)', 0);
|
||||
create view uv_fpo_atomic_view as select id, valid_at, b from uv_fpo_atomic_tab;
|
||||
create function uv_fpo_atomic_fn() returns void language sql begin atomic
|
||||
update uv_fpo_atomic_view
|
||||
for portion of valid_at from '2010-01-01' to '2020-01-01'
|
||||
set b = 99 where id = '[1,1]';
|
||||
end;
|
||||
create trigger uv_fpo_atomic_instead
|
||||
instead of update on uv_fpo_atomic_view
|
||||
for each row execute function uv_fpo_instead_trig();
|
||||
-- Would crash if we checked at parse-time:
|
||||
select uv_fpo_atomic_fn();
|
||||
ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
|
||||
CONTEXT: SQL function "uv_fpo_atomic_fn" statement 1
|
||||
drop function uv_fpo_atomic_fn();
|
||||
drop table uv_fpo_atomic_tab cascade;
|
||||
NOTICE: drop cascades to view uv_fpo_atomic_view
|
||||
drop function uv_fpo_instead_trig();
|
||||
|
|
|
|||
|
|
@ -2148,3 +2148,76 @@ values (1, 2, default, 5, 4, default, 3), (10, 11, 'C value', 14, 13, 100, 12);
|
|||
select * from base_tab order by a;
|
||||
drop view base_tab_view;
|
||||
drop table base_tab;
|
||||
|
||||
-- FOR PORTION OF is not supported on views with INSTEAD OF triggers
|
||||
create view uv_fpo_instead_view as select id, valid_at, b from uv_fpo_tab;
|
||||
|
||||
create function uv_fpo_instead_trig() returns trigger language plpgsql as
|
||||
$$ begin return null; end $$;
|
||||
|
||||
create trigger uv_fpo_instead_upd_trig
|
||||
instead of update on uv_fpo_instead_view
|
||||
for each row execute function uv_fpo_instead_trig();
|
||||
create trigger uv_fpo_instead_del_trig
|
||||
instead of delete on uv_fpo_instead_view
|
||||
for each row execute function uv_fpo_instead_trig();
|
||||
|
||||
update uv_fpo_instead_view
|
||||
for portion of valid_at from '2015-01-01' to '2020-01-01'
|
||||
set b = 99 where id = '[1,1]'; -- error
|
||||
|
||||
delete from uv_fpo_instead_view
|
||||
for portion of valid_at from '2017-01-01' to '2022-01-01'
|
||||
where id = '[1,1]'; -- error
|
||||
|
||||
-- The check does not depend on which rows match, so it errors even when
|
||||
-- no rows do.
|
||||
update uv_fpo_instead_view
|
||||
for portion of valid_at from '2015-01-01' to '2020-01-01'
|
||||
set b = 99 where id = '[9,9]'; -- error, even with no matching rows
|
||||
|
||||
delete from uv_fpo_instead_view
|
||||
for portion of valid_at from '2017-01-01' to '2022-01-01'
|
||||
where id = '[9,9]'; -- error, even with no matching rows
|
||||
|
||||
drop view uv_fpo_instead_view;
|
||||
drop function uv_fpo_instead_trig();
|
||||
|
||||
-- Forbid INSTEAD OF triggers with FOR PORTION OF even if the FOR PORTION OF
|
||||
-- statement is parsed before the trigger exists.
|
||||
-- This can happen in at least a couple ways: a rewrite rule or a BEGIN ATOMIC function.
|
||||
create function uv_fpo_instead_trig() returns trigger language plpgsql as
|
||||
$$ begin return new; end $$;
|
||||
|
||||
-- via a rewrite rule
|
||||
create table uv_fpo_rule_tab (id int4range, valid_at tsrange, b float);
|
||||
insert into uv_fpo_rule_tab values ('[1,1]', '[2000-01-01, 2030-01-01)', 0);
|
||||
create view uv_fpo_rule_view as select id, valid_at, b from uv_fpo_rule_tab;
|
||||
create rule uv_fpo_rule as on insert to uv_fpo_rule_tab do also
|
||||
update uv_fpo_rule_view
|
||||
for portion of valid_at from '2010-01-01' to '2020-01-01'
|
||||
set b = 99 where id = '[1,1]';
|
||||
create trigger uv_fpo_rule_instead
|
||||
instead of update on uv_fpo_rule_view
|
||||
for each row execute function uv_fpo_instead_trig();
|
||||
-- Would crash if we checked at parse-time:
|
||||
insert into uv_fpo_rule_tab values ('[2,2]', '[2000-01-01,2030-01-01)', 0);
|
||||
drop table uv_fpo_rule_tab cascade;
|
||||
|
||||
-- via a BEGIN ATOMIC function body
|
||||
create table uv_fpo_atomic_tab (id int4range, valid_at tsrange, b float);
|
||||
insert into uv_fpo_atomic_tab values ('[1,1]', '[2000-01-01, 2030-01-01)', 0);
|
||||
create view uv_fpo_atomic_view as select id, valid_at, b from uv_fpo_atomic_tab;
|
||||
create function uv_fpo_atomic_fn() returns void language sql begin atomic
|
||||
update uv_fpo_atomic_view
|
||||
for portion of valid_at from '2010-01-01' to '2020-01-01'
|
||||
set b = 99 where id = '[1,1]';
|
||||
end;
|
||||
create trigger uv_fpo_atomic_instead
|
||||
instead of update on uv_fpo_atomic_view
|
||||
for each row execute function uv_fpo_instead_trig();
|
||||
-- Would crash if we checked at parse-time:
|
||||
select uv_fpo_atomic_fn();
|
||||
drop function uv_fpo_atomic_fn();
|
||||
drop table uv_fpo_atomic_tab cascade;
|
||||
drop function uv_fpo_instead_trig();
|
||||
|
|
|
|||
Loading…
Reference in a new issue