mirror of
https://github.com/postgres/postgres.git
synced 2025-05-29 16:21:20 +03:00
Correctly check updatability of columns targeted by INSERT...DEFAULT.
If a view has some updatable and some non-updatable columns, we failed to verify updatability of any columns for which an INSERT or UPDATE on the view explicitly specifies a DEFAULT item (unless the view has a declared default for that column, which is rare anyway, and one would almost certainly not write one for a non-updatable column). This would lead to an unexpected "attribute number N not found in view targetlist" error rather than the intended error. Per bug #18546 from Alexander Lakhin. This bug is old, so back-patch to all supported branches. Discussion: https://postgr.es/m/18546-84a292e759a9361d@postgresql.org
This commit is contained in:
parent
b82791c8fc
commit
96953052a1
@ -2987,7 +2987,7 @@ relation_is_updatable(Oid reloid,
|
|||||||
*
|
*
|
||||||
* This is used with simply-updatable views to map column-permissions sets for
|
* This is used with simply-updatable views to map column-permissions sets for
|
||||||
* the view columns onto the matching columns in the underlying base relation.
|
* the view columns onto the matching columns in the underlying base relation.
|
||||||
* The targetlist is expected to be a list of plain Vars of the underlying
|
* Relevant entries in the targetlist must be plain Vars of the underlying
|
||||||
* relation (as per the checks above in view_query_is_auto_updatable).
|
* relation (as per the checks above in view_query_is_auto_updatable).
|
||||||
*/
|
*/
|
||||||
static Bitmapset *
|
static Bitmapset *
|
||||||
@ -3084,6 +3084,9 @@ rewriteTargetView(Query *parsetree, Relation view)
|
|||||||
*/
|
*/
|
||||||
viewquery = copyObject(get_view_query(view));
|
viewquery = copyObject(get_view_query(view));
|
||||||
|
|
||||||
|
/* Locate RTE describing the view in the outer query */
|
||||||
|
view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
|
||||||
|
|
||||||
/* The view must be updatable, else fail */
|
/* The view must be updatable, else fail */
|
||||||
auto_update_detail =
|
auto_update_detail =
|
||||||
view_query_is_auto_updatable(viewquery,
|
view_query_is_auto_updatable(viewquery,
|
||||||
@ -3126,17 +3129,26 @@ rewriteTargetView(Query *parsetree, Relation view)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For INSERT/UPDATE the modified columns must all be updatable. Note that
|
* For INSERT/UPDATE the modified columns must all be updatable.
|
||||||
* we get the modified columns from the query's targetlist, not from the
|
|
||||||
* result RTE's insertedCols and/or updatedCols set, since
|
|
||||||
* rewriteTargetListIU may have added additional targetlist entries for
|
|
||||||
* view defaults, and these must also be updatable.
|
|
||||||
*/
|
*/
|
||||||
if (parsetree->commandType != CMD_DELETE)
|
if (parsetree->commandType != CMD_DELETE)
|
||||||
{
|
{
|
||||||
Bitmapset *modified_cols = NULL;
|
Bitmapset *modified_cols;
|
||||||
char *non_updatable_col;
|
char *non_updatable_col;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the set of modified columns as those listed in the result
|
||||||
|
* RTE's insertedCols and/or updatedCols sets plus those that are
|
||||||
|
* targets of the query's targetlist(s). We must consider the query's
|
||||||
|
* targetlist because rewriteTargetListIU may have added additional
|
||||||
|
* targetlist entries for view defaults, and these must also be
|
||||||
|
* updatable. But rewriteTargetListIU can also remove entries if they
|
||||||
|
* are DEFAULT markers and the column's default is NULL, so
|
||||||
|
* considering only the targetlist would also be wrong.
|
||||||
|
*/
|
||||||
|
modified_cols = bms_union(view_rte->insertedCols,
|
||||||
|
view_rte->updatedCols);
|
||||||
|
|
||||||
foreach(lc, parsetree->targetList)
|
foreach(lc, parsetree->targetList)
|
||||||
{
|
{
|
||||||
TargetEntry *tle = (TargetEntry *) lfirst(lc);
|
TargetEntry *tle = (TargetEntry *) lfirst(lc);
|
||||||
@ -3194,9 +3206,6 @@ rewriteTargetView(Query *parsetree, Relation view)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Locate RTE describing the view in the outer query */
|
|
||||||
view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we get here, view_query_is_auto_updatable() has verified that the
|
* If we get here, view_query_is_auto_updatable() has verified that the
|
||||||
* view contains a single base relation.
|
* view contains a single base relation.
|
||||||
|
@ -1598,6 +1598,9 @@ DETAIL: View columns that refer to system columns are not updatable.
|
|||||||
INSERT INTO rw_view1 (s, c, a) VALUES (null, null, 1.1); -- should fail
|
INSERT INTO rw_view1 (s, c, a) VALUES (null, null, 1.1); -- should fail
|
||||||
ERROR: cannot insert into column "s" of view "rw_view1"
|
ERROR: cannot insert into column "s" of view "rw_view1"
|
||||||
DETAIL: View columns that are not columns of their base relation are not updatable.
|
DETAIL: View columns that are not columns of their base relation are not updatable.
|
||||||
|
INSERT INTO rw_view1 (s, c, a) VALUES (default, default, 1.1); -- should fail
|
||||||
|
ERROR: cannot insert into column "s" of view "rw_view1"
|
||||||
|
DETAIL: View columns that are not columns of their base relation are not updatable.
|
||||||
INSERT INTO rw_view1 (a) VALUES (1.1) RETURNING a, s, c; -- OK
|
INSERT INTO rw_view1 (a) VALUES (1.1) RETURNING a, s, c; -- OK
|
||||||
a | s | c
|
a | s | c
|
||||||
-----+-------------------+-------------------
|
-----+-------------------+-------------------
|
||||||
|
@ -845,6 +845,7 @@ CREATE VIEW rw_view1 AS
|
|||||||
|
|
||||||
INSERT INTO rw_view1 VALUES (null, null, 1.1, null); -- should fail
|
INSERT INTO rw_view1 VALUES (null, null, 1.1, null); -- should fail
|
||||||
INSERT INTO rw_view1 (s, c, a) VALUES (null, null, 1.1); -- should fail
|
INSERT INTO rw_view1 (s, c, a) VALUES (null, null, 1.1); -- should fail
|
||||||
|
INSERT INTO rw_view1 (s, c, a) VALUES (default, default, 1.1); -- should fail
|
||||||
INSERT INTO rw_view1 (a) VALUES (1.1) RETURNING a, s, c; -- OK
|
INSERT INTO rw_view1 (a) VALUES (1.1) RETURNING a, s, c; -- OK
|
||||||
UPDATE rw_view1 SET s = s WHERE a = 1.1; -- should fail
|
UPDATE rw_view1 SET s = s WHERE a = 1.1; -- should fail
|
||||||
UPDATE rw_view1 SET a = 1.05 WHERE a = 1.1 RETURNING s; -- OK
|
UPDATE rw_view1 SET a = 1.05 WHERE a = 1.1 RETURNING s; -- OK
|
||||||
|
Loading…
x
Reference in New Issue
Block a user