1
0
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:
Peter Eisentraut
2026-05-13 13:34:09 +02:00
parent 6636621782
commit 7ca8c94296
3 changed files with 72 additions and 0 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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