Skip to content

Commit 220003b

Browse files
committed
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
1 parent 8720a15 commit 220003b

File tree

3 files changed

+25
-14
lines changed

3 files changed

+25
-14
lines changed

src/backend/rewrite/rewriteHandler.c

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,7 +2986,7 @@ relation_is_updatable(Oid reloid,
29862986
*
29872987
* This is used with simply-updatable views to map column-permissions sets for
29882988
* the view columns onto the matching columns in the underlying base relation.
2989-
* The targetlist is expected to be a list of plain Vars of the underlying
2989+
* Relevant entries in the targetlist must be plain Vars of the underlying
29902990
* relation (as per the checks above in view_query_is_auto_updatable).
29912991
*/
29922992
static Bitmapset *
@@ -3186,6 +3186,10 @@ rewriteTargetView(Query *parsetree, Relation view)
31863186
*/
31873187
viewquery = copyObject(get_view_query(view));
31883188

3189+
/* Locate RTE and perminfo describing the view in the outer query */
3190+
view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
3191+
view_perminfo = getRTEPermissionInfo(parsetree->rteperminfos, view_rte);
3192+
31893193
/*
31903194
* Are we doing INSERT/UPDATE, or MERGE containing INSERT/UPDATE? If so,
31913195
* various additional checks on the view columns need to be applied, and
@@ -3225,17 +3229,26 @@ rewriteTargetView(Query *parsetree, Relation view)
32253229

32263230
/*
32273231
* For INSERT/UPDATE (or MERGE containing INSERT/UPDATE) the modified
3228-
* columns must all be updatable. Note that we get the modified columns
3229-
* from the query's targetlist, not from the result RTE's insertedCols
3230-
* and/or updatedCols set, since rewriteTargetListIU may have added
3231-
* additional targetlist entries for view defaults, and these must also be
3232-
* updatable.
3232+
* columns must all be updatable.
32333233
*/
32343234
if (insert_or_update)
32353235
{
3236-
Bitmapset *modified_cols = NULL;
3236+
Bitmapset *modified_cols;
32373237
char *non_updatable_col;
32383238

3239+
/*
3240+
* Compute the set of modified columns as those listed in the result
3241+
* RTE's insertedCols and/or updatedCols sets plus those that are
3242+
* targets of the query's targetlist(s). We must consider the query's
3243+
* targetlist because rewriteTargetListIU may have added additional
3244+
* targetlist entries for view defaults, and these must also be
3245+
* updatable. But rewriteTargetListIU can also remove entries if they
3246+
* are DEFAULT markers and the column's default is NULL, so
3247+
* considering only the targetlist would also be wrong.
3248+
*/
3249+
modified_cols = bms_union(view_perminfo->insertedCols,
3250+
view_perminfo->updatedCols);
3251+
32393252
foreach(lc, parsetree->targetList)
32403253
{
32413254
TargetEntry *tle = (TargetEntry *) lfirst(lc);
@@ -3337,9 +3350,6 @@ rewriteTargetView(Query *parsetree, Relation view)
33373350
}
33383351
}
33393352

3340-
/* Locate RTE describing the view in the outer query */
3341-
view_rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
3342-
33433353
/*
33443354
* If we get here, view_query_is_auto_updatable() has verified that the
33453355
* view contains a single base relation.
@@ -3434,10 +3444,7 @@ rewriteTargetView(Query *parsetree, Relation view)
34343444
* Note: the original view's RTEPermissionInfo remains in the query's
34353445
* rteperminfos so that the executor still performs appropriate
34363446
* permissions checks for the query caller's use of the view.
3437-
*/
3438-
view_perminfo = getRTEPermissionInfo(parsetree->rteperminfos, view_rte);
3439-
3440-
/*
3447+
*
34413448
* Disregard the perminfo in viewquery->rteperminfos that the base_rte
34423449
* would currently be pointing at, because we'd like it to point now to a
34433450
* new one that will be filled below. Must set perminfoindex to 0 to not

src/test/regress/expected/updatable_views.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,9 @@ DETAIL: View columns that refer to system columns are not updatable.
21012101
INSERT INTO rw_view1 (s, c, a) VALUES (null, null, 1.1); -- should fail
21022102
ERROR: cannot insert into column "s" of view "rw_view1"
21032103
DETAIL: View columns that are not columns of their base relation are not updatable.
2104+
INSERT INTO rw_view1 (s, c, a) VALUES (default, default, 1.1); -- should fail
2105+
ERROR: cannot insert into column "s" of view "rw_view1"
2106+
DETAIL: View columns that are not columns of their base relation are not updatable.
21042107
INSERT INTO rw_view1 (a) VALUES (1.1) RETURNING a, s, c; -- OK
21052108
a | s | c
21062109
-----+-------------------+-------------------

src/test/regress/sql/updatable_views.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,7 @@ CREATE VIEW rw_view1 AS
11111111

11121112
INSERT INTO rw_view1 VALUES (null, null, 1.1, null); -- should fail
11131113
INSERT INTO rw_view1 (s, c, a) VALUES (null, null, 1.1); -- should fail
1114+
INSERT INTO rw_view1 (s, c, a) VALUES (default, default, 1.1); -- should fail
11141115
INSERT INTO rw_view1 (a) VALUES (1.1) RETURNING a, s, c; -- OK
11151116
UPDATE rw_view1 SET s = s WHERE a = 1.1; -- should fail
11161117
UPDATE rw_view1 SET a = 1.05 WHERE a = 1.1 RETURNING s; -- OK

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy