mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Fix FOR PORTION OF with non-updatable view columns
Both UPDATE and DELETE were failing to test that the application-time column was updatable. The column is not part of perminfo->updatedCols, because it should not be checked for permissions. And it needs to be checked in the DELETE case as well, since we might insert leftovers with a value for that column. Author: Paul A. Jungwirth <pj@illuminatedcomputing.com> Co-authored-by: jian he <jian.universality@gmail.com> Discussion: https://www.postgresql.org/message-id/CACJufxFRqg8%3DgbZ-Q6ZS_UQ%2BYdwfZpk%2B9rf7jgWrk8m4RMUm%3DA%40mail.gmail.com
This commit is contained in:
@@ -3481,6 +3481,53 @@ rewriteTargetView(Query *parsetree, Relation view)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Similarly, make sure the FOR PORTION OF column is updateable. This is
|
||||
* not included in the columns tested above, and we have to test it even
|
||||
* for DELETEs.
|
||||
*/
|
||||
if (parsetree->forPortionOf)
|
||||
{
|
||||
AttrNumber rangeAttno;
|
||||
Bitmapset *fpo_cols;
|
||||
char *non_updatable_col;
|
||||
const char *fpo_update_detail;
|
||||
|
||||
rangeAttno = parsetree->forPortionOf->rangeVar->varattno;
|
||||
fpo_cols = bms_make_singleton(rangeAttno - FirstLowInvalidHeapAttributeNumber);
|
||||
|
||||
fpo_update_detail = view_cols_are_auto_updatable(viewquery,
|
||||
fpo_cols,
|
||||
NULL,
|
||||
&non_updatable_col);
|
||||
if (fpo_update_detail)
|
||||
{
|
||||
switch (parsetree->commandType)
|
||||
{
|
||||
case CMD_UPDATE:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot update column \"%s\" of view \"%s\"",
|
||||
non_updatable_col,
|
||||
RelationGetRelationName(view)),
|
||||
errdetail_internal("%s", _(fpo_update_detail))));
|
||||
break;
|
||||
case CMD_DELETE:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot delete from view \"%s\" using FOR PORTION OF \"%s\"",
|
||||
RelationGetRelationName(view),
|
||||
non_updatable_col),
|
||||
errdetail_internal("%s", _(fpo_update_detail))));
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized CmdType: %d",
|
||||
(int) parsetree->commandType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For MERGE, there must not be any INSTEAD OF triggers on an otherwise
|
||||
* updatable view. The caller already checked that there isn't a full set
|
||||
|
||||
@@ -3754,6 +3754,20 @@ select * from uv_fpo_view order by id, valid_at;
|
||||
0 | 1 | ["Sat Jan 01 00:00:00 2022","Tue Jan 01 00:00:00 2030") | [1,2) | 2.0
|
||||
(3 rows)
|
||||
|
||||
-- UPDATE/DELETE FOR PORTION fails if the column is not updatable
|
||||
-- (e.g. a computed expression, not a base column):
|
||||
create view uv_fpo_view_nonupd as
|
||||
select id, '[1,20]'::int4range as valid_at, b
|
||||
from uv_fpo_tab;
|
||||
-- Updating fails:
|
||||
update uv_fpo_view_nonupd for portion of valid_at from 1 to 10 set b = 2;
|
||||
ERROR: cannot update column "valid_at" of view "uv_fpo_view_nonupd"
|
||||
DETAIL: View columns that are not columns of their base relation are not updatable.
|
||||
-- Deleting fails:
|
||||
delete from uv_fpo_view_nonupd for portion of valid_at from 1 to 10;
|
||||
ERROR: cannot delete from view "uv_fpo_view_nonupd" using FOR PORTION OF "valid_at"
|
||||
DETAIL: View columns that are not columns of their base relation are not updatable.
|
||||
drop view uv_fpo_view_nonupd;
|
||||
-- Test whole-row references to the view
|
||||
create table uv_iocu_tab (a int unique, b text);
|
||||
create view uv_iocu_view as
|
||||
|
||||
@@ -1903,6 +1903,17 @@ select * from uv_fpo_view order by id, valid_at;
|
||||
delete from uv_fpo_view for portion of valid_at from '2017-01-01' to '2022-01-01' where id = '[1,1]';
|
||||
select * from uv_fpo_view order by id, valid_at;
|
||||
|
||||
-- UPDATE/DELETE FOR PORTION fails if the column is not updatable
|
||||
-- (e.g. a computed expression, not a base column):
|
||||
create view uv_fpo_view_nonupd as
|
||||
select id, '[1,20]'::int4range as valid_at, b
|
||||
from uv_fpo_tab;
|
||||
-- Updating fails:
|
||||
update uv_fpo_view_nonupd for portion of valid_at from 1 to 10 set b = 2;
|
||||
-- Deleting fails:
|
||||
delete from uv_fpo_view_nonupd for portion of valid_at from 1 to 10;
|
||||
drop view uv_fpo_view_nonupd;
|
||||
|
||||
-- Test whole-row references to the view
|
||||
create table uv_iocu_tab (a int unique, b text);
|
||||
create view uv_iocu_view as
|
||||
|
||||
Reference in New Issue
Block a user