Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5a19da5

Browse files
committed
Fix more bugs caused by adding columns to the end of a view.
If a view is defined atop another view, and then CREATE OR REPLACEVIEW is used to add columns to the lower view, then when the upperview's referencing RTE is expanded by ApplyRetrieveRule we will havea subquery RTE with fewer eref->colnames than output columns. Thisconfuses various code that assumes those lists are always in sync,as they are in plain parser output.We have seen such problems before (cf commitd5b760e), and nowI think the time has come to do what was speculated about in thatcommit: let's make ApplyRetrieveRule synthesize some column names topreserve the invariant that holds in parser output. Otherwise we'llbe chasing this class of bugs indefinitely. Moreover, it appears fromtesting that this actually gives us better results in the test cased5b760e added, and likely in other corner cases that we lackcoverage for.In HEAD, I replacedd5b760e's hack to make expandRTE exit early withan elog(ERROR) call, since the case is now presumably unreachable.But it seems like changing that in back branches would bring more riskthan benefit, so there I just updated the comment.Per bug #17811 from Alexander Lakhin. Back-patch to all supportedbranches.Discussion:https://postgr.es/m/17811-d31686b78f0dffc9@postgresql.org
1 parent23b75dd commit5a19da5

File tree

4 files changed

+82
-14
lines changed

4 files changed

+82
-14
lines changed

‎src/backend/parser/parse_relation.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2297,12 +2297,17 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
22972297
Assert(varattno==te->resno);
22982298

22992299
/*
2300-
* In scenarios where columns have been added to a view
2301-
* since the outer query was originally parsed, there can
2302-
* be more items in the subquery tlist than the outer
2303-
* query expects. We should ignore such extra column(s)
2304-
* --- compare the behavior for composite-returning
2305-
* functions, in the RTE_FUNCTION case below.
2300+
* In a just-parsed subquery RTE, rte->eref->colnames
2301+
* should always have exactly as many entries as the
2302+
* subquery has non-junk output columns. However, if the
2303+
* subquery RTE was created by expansion of a view,
2304+
* perhaps the subquery tlist could now have more entries
2305+
* than existed when the outer query was parsed. Such
2306+
* cases should now be prevented because ApplyRetrieveRule
2307+
* will extend the colnames list to match. But out of
2308+
* caution, we'll keep the code like this in the back
2309+
* branches: just ignore any columns that lack colnames
2310+
* entries.
23062311
*/
23072312
if (!aliasp_item)
23082313
break;

‎src/backend/rewrite/rewriteHandler.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include"catalog/dependency.h"
2727
#include"catalog/pg_type.h"
2828
#include"commands/trigger.h"
29+
#include"executor/executor.h"
2930
#include"foreign/fdwapi.h"
3031
#include"miscadmin.h"
3132
#include"nodes/makefuncs.h"
@@ -1703,6 +1704,7 @@ ApplyRetrieveRule(Query *parsetree,
17031704
RangeTblEntry*rte,
17041705
*subrte;
17051706
RowMarkClause*rc;
1707+
intnumCols;
17061708

17071709
if (list_length(rule->actions)!=1)
17081710
elog(ERROR,"expected just one rule action");
@@ -1862,6 +1864,20 @@ ApplyRetrieveRule(Query *parsetree,
18621864
rte->updatedCols=NULL;
18631865
rte->extraUpdatedCols=NULL;
18641866

1867+
/*
1868+
* Since we allow CREATE OR REPLACE VIEW to add columns to a view, the
1869+
* rule_action might emit more columns than we expected when the current
1870+
* query was parsed. Various places expect rte->eref->colnames to be
1871+
* consistent with the non-junk output columns of the subquery, so patch
1872+
* things up if necessary by adding some dummy column names.
1873+
*/
1874+
numCols=ExecCleanTargetListLength(rule_action->targetList);
1875+
while (list_length(rte->eref->colnames)<numCols)
1876+
{
1877+
rte->eref->colnames=lappend(rte->eref->colnames,
1878+
makeString(pstrdup("?column?")));
1879+
}
1880+
18651881
returnparsetree;
18661882
}
18671883

‎src/test/regress/expected/alter_table.out

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2536,22 +2536,51 @@ View definition:
25362536
FROM at_view_1 v1;
25372537

25382538
explain (verbose, costs off) select * from at_view_2;
2539-
QUERY PLAN
2540-
----------------------------------------------------------------
2539+
QUERY PLAN
2540+
-------------------------------------------------------------
25412541
Seq Scan on public.at_base_table bt
2542-
Output: bt.id, bt.stuff, to_json(ROW(bt.id, bt.stuff,NULL))
2542+
Output: bt.id, bt.stuff, to_json(ROW(bt.id, bt.stuff,4))
25432543
(2 rows)
25442544

25452545
select * from at_view_2;
2546-
id | stuff | j
2547-
----+--------+----------------------------------------
2548-
23 | skidoo | {"id":23,"stuff":"skidoo","more":null}
2546+
id | stuff |j
2547+
----+--------+-------------------------------------
2548+
23 | skidoo | {"id":23,"stuff":"skidoo","more":4}
25492549
(1 row)
25502550

25512551
drop view at_view_2;
25522552
drop view at_view_1;
25532553
drop table at_base_table;
2554-
-- check adding a column not iself requiring a rewrite, together with
2554+
-- related case (bug #17811)
2555+
begin;
2556+
create temp table t1 as select * from int8_tbl;
2557+
create temp view v1 as select 1::int8 as q1;
2558+
create temp view v2 as select * from v1;
2559+
create or replace temp view v1 with (security_barrier = true)
2560+
as select * from t1;
2561+
create temp table log (q1 int8, q2 int8);
2562+
create rule v1_upd_rule as on update to v1
2563+
do also insert into log values (new.*);
2564+
update v2 set q1 = q1 + 1 where q1 = 123;
2565+
select * from t1;
2566+
q1 | q2
2567+
------------------+-------------------
2568+
4567890123456789 | 123
2569+
4567890123456789 | 4567890123456789
2570+
4567890123456789 | -4567890123456789
2571+
124 | 456
2572+
124 | 4567890123456789
2573+
(5 rows)
2574+
2575+
select * from log;
2576+
q1 | q2
2577+
-----+------------------
2578+
124 | 456
2579+
124 | 4567890123456789
2580+
(2 rows)
2581+
2582+
rollback;
2583+
-- check adding a column not itself requiring a rewrite, together with
25552584
-- a column requiring a default (bug #16038)
25562585
-- ensure that rewrites aren't silently optimized away, removing the
25572586
-- value of the test

‎src/test/regress/sql/alter_table.sql

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1623,7 +1623,25 @@ drop view at_view_2;
16231623
dropview at_view_1;
16241624
droptable at_base_table;
16251625

1626-
-- check adding a column not iself requiring a rewrite, together with
1626+
-- related case (bug #17811)
1627+
begin;
1628+
create temp table t1asselect*from int8_tbl;
1629+
create temp view v1asselect1::int8as q1;
1630+
create temp view v2asselect*from v1;
1631+
createor replace temp view v1 with (security_barrier= true)
1632+
asselect*from t1;
1633+
1634+
create temp table log (q1 int8, q2 int8);
1635+
createrulev1_upd_ruleasonupdate to v1
1636+
do alsoinsert into logvalues (new.*);
1637+
1638+
update v2set q1= q1+1where q1=123;
1639+
1640+
select*from t1;
1641+
select*from log;
1642+
rollback;
1643+
1644+
-- check adding a column not itself requiring a rewrite, together with
16271645
-- a column requiring a default (bug #16038)
16281646

16291647
-- ensure that rewrites aren't silently optimized away, removing the

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp