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

Commitc2fa113

Browse files
committed
Close old gap in dependency checks for functions returning composite.
The dependency logic failed to register a column-level dependencywhen a view or rule contains a reference to a specific column ofthe result of a function-returning-composite. That meant you coulddrop the column from the composite type, causing trouble for futureexecutions of the view. We've known about this for years, but neversummoned the energy to actually fix it, instead installing variouslow-level defenses to prevent crashing on references to dropped columns.We had to do that to plug the hole in stable branches, where there mightbe pre-existing broken references; but let's fix the root cause today.To do that, add some logic (borrowed from get_rte_attribute_is_dropped)to find_expr_references_walker, to check whether a Var referencing anRTE_FUNCTION RTE is referencing a column of a composite type, and ifso add the proper dependency.However ... it seems mighty unwise to remove said low-level defenses,since there could be other bugs now or in the future that allowreaching them. By the same token, letting those defenses go untestedseems unwise. Hence, rather than just dropping the associated testcases, hack them to continue working by the expedient of manuallydropping the pg_depend entries that this fix installs.Back-patch into v15. I don't want to risk changing this behaviorin stable branches, but it seems not too late for v15. (Sincewe have already forced initdb for beta3, we can be sure that allproduction v15 installations will have these added dependencies.)Discussion:https://postgr.es/m/182492.1658431155@sss.pgh.pa.us
1 parent00cf403 commitc2fa113

File tree

6 files changed

+267
-7
lines changed

6 files changed

+267
-7
lines changed

‎src/backend/catalog/dependency.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
#include"commands/sequence.h"
7575
#include"commands/trigger.h"
7676
#include"commands/typecmds.h"
77+
#include"funcapi.h"
7778
#include"nodes/nodeFuncs.h"
7879
#include"parser/parsetree.h"
7980
#include"rewrite/rewriteRemove.h"
@@ -205,6 +206,8 @@ static void deleteOneObject(const ObjectAddress *object,
205206
staticvoiddoDeletion(constObjectAddress*object,intflags);
206207
staticboolfind_expr_references_walker(Node*node,
207208
find_expr_references_context*context);
209+
staticvoidprocess_function_rte_ref(RangeTblEntry*rte,AttrNumberattnum,
210+
find_expr_references_context*context);
208211
staticvoideliminate_duplicate_dependencies(ObjectAddresses*addrs);
209212
staticintobject_address_comparator(constvoid*a,constvoid*b);
210213
staticvoidadd_object_address(ObjectClassoclass,OidobjectId,int32subId,
@@ -1769,6 +1772,12 @@ find_expr_references_walker(Node *node,
17691772
add_object_address(OCLASS_CLASS,rte->relid,var->varattno,
17701773
context->addrs);
17711774
}
1775+
elseif (rte->rtekind==RTE_FUNCTION)
1776+
{
1777+
/* Might need to add a dependency on a composite type's column */
1778+
/* (done out of line, because it's a bit bulky) */
1779+
process_function_rte_ref(rte,var->varattno,context);
1780+
}
17721781

17731782
/*
17741783
* Vars referencing other RTE types require no additional work. In
@@ -2343,6 +2352,65 @@ find_expr_references_walker(Node *node,
23432352
(void*)context);
23442353
}
23452354

2355+
/*
2356+
* find_expr_references_walker subroutine: handle a Var reference
2357+
* to an RTE_FUNCTION RTE
2358+
*/
2359+
staticvoid
2360+
process_function_rte_ref(RangeTblEntry*rte,AttrNumberattnum,
2361+
find_expr_references_context*context)
2362+
{
2363+
intatts_done=0;
2364+
ListCell*lc;
2365+
2366+
/*
2367+
* Identify which RangeTblFunction produces this attnum, and see if it
2368+
* returns a composite type. If so, we'd better make a dependency on the
2369+
* referenced column of the composite type (or actually, of its associated
2370+
* relation).
2371+
*/
2372+
foreach(lc,rte->functions)
2373+
{
2374+
RangeTblFunction*rtfunc= (RangeTblFunction*)lfirst(lc);
2375+
2376+
if (attnum>atts_done&&
2377+
attnum <=atts_done+rtfunc->funccolcount)
2378+
{
2379+
TupleDesctupdesc;
2380+
2381+
tupdesc=get_expr_result_tupdesc(rtfunc->funcexpr, true);
2382+
if (tupdesc&&tupdesc->tdtypeid!=RECORDOID)
2383+
{
2384+
/*
2385+
* Named composite type, so individual columns could get
2386+
* dropped. Make a dependency on this specific column.
2387+
*/
2388+
Oidreltype=get_typ_typrelid(tupdesc->tdtypeid);
2389+
2390+
Assert(attnum-atts_done <=tupdesc->natts);
2391+
if (OidIsValid(reltype))/* can this fail? */
2392+
add_object_address(OCLASS_CLASS,reltype,
2393+
attnum-atts_done,
2394+
context->addrs);
2395+
return;
2396+
}
2397+
/* Nothing to do; function's result type is handled elsewhere */
2398+
return;
2399+
}
2400+
atts_done+=rtfunc->funccolcount;
2401+
}
2402+
2403+
/* If we get here, must be looking for the ordinality column */
2404+
if (rte->funcordinality&&attnum==atts_done+1)
2405+
return;
2406+
2407+
/* this probably can't happen ... */
2408+
ereport(ERROR,
2409+
(errcode(ERRCODE_UNDEFINED_COLUMN),
2410+
errmsg("column %d of relation \"%s\" does not exist",
2411+
attnum,rte->eref->aliasname)));
2412+
}
2413+
23462414
/*
23472415
* Given an array of dependency references, eliminate any duplicates.
23482416
*/

‎src/backend/utils/adt/ruleutils.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7333,9 +7333,9 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
73337333
/*
73347334
* If we find a Var referencing a dropped column, it seems better to
73357335
* print something (anything) than to fail. In general this should
7336-
* not happen, butthere are specificcases involving functions
7337-
* returning named composite types where we don't sufficiently enforce
7338-
*that you can't drop a column that's referenced in some view.
7336+
* not happen, butit used to be possible for somecases involving
7337+
*functionsreturning named composite types, and perhaps there are
7338+
*still bugs out there.
73397339
*/
73407340
if (attname==NULL)
73417341
attname="?dropped?column?";

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

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,8 +1597,29 @@ select * from tt14v;
15971597
foo | baz | 42
15981598
(1 row)
15991599

1600+
alter table tt14t drop column f3; -- fail, view has explicit reference to f3
1601+
ERROR: cannot drop column f3 of table tt14t because other objects depend on it
1602+
DETAIL: view tt14v depends on column f3 of table tt14t
1603+
HINT: Use DROP ... CASCADE to drop the dependent objects too.
1604+
-- We used to have a bug that would allow the above to succeed, posing
1605+
-- hazards for later execution of the view. Check that the internal
1606+
-- defenses for those hazards haven't bit-rotted, in case some other
1607+
-- bug with similar symptoms emerges.
16001608
begin;
1601-
-- this perhaps should be rejected, but it isn't:
1609+
-- destroy the dependency entry that prevents the DROP:
1610+
delete from pg_depend where
1611+
objid = (select oid from pg_rewrite
1612+
where ev_class = 'tt14v'::regclass and rulename = '_RETURN')
1613+
and refobjsubid = 3
1614+
returning pg_describe_object(classid, objid, objsubid) as obj,
1615+
pg_describe_object(refclassid, refobjid, refobjsubid) as ref,
1616+
deptype;
1617+
obj | ref | deptype
1618+
----------------------------+--------------------------+---------
1619+
rule _RETURN on view tt14v | column f3 of table tt14t | n
1620+
(1 row)
1621+
1622+
-- this will now succeed:
16021623
alter table tt14t drop column f3;
16031624
-- column f3 is still in the view, sort of ...
16041625
select pg_get_viewdef('tt14v', true);
@@ -1629,8 +1650,26 @@ select f1, f4 from tt14v;
16291650
select * from tt14v;
16301651
ERROR: attribute 3 of type record has been dropped
16311652
rollback;
1653+
-- likewise, altering a referenced column's type is prohibited ...
1654+
alter table tt14t alter column f4 type integer using f4::integer; -- fail
1655+
ERROR: cannot alter type of a column used by a view or rule
1656+
DETAIL: rule _RETURN on view tt14v depends on column "f4"
1657+
-- ... but some bug might let it happen, so check defenses
16321658
begin;
1633-
-- this perhaps should be rejected, but it isn't:
1659+
-- destroy the dependency entry that prevents the ALTER:
1660+
delete from pg_depend where
1661+
objid = (select oid from pg_rewrite
1662+
where ev_class = 'tt14v'::regclass and rulename = '_RETURN')
1663+
and refobjsubid = 4
1664+
returning pg_describe_object(classid, objid, objsubid) as obj,
1665+
pg_describe_object(refclassid, refobjid, refobjsubid) as ref,
1666+
deptype;
1667+
obj | ref | deptype
1668+
----------------------------+--------------------------+---------
1669+
rule _RETURN on view tt14v | column f4 of table tt14t | n
1670+
(1 row)
1671+
1672+
-- this will now succeed:
16341673
alter table tt14t alter column f4 type integer using f4::integer;
16351674
-- f4 is still in the view ...
16361675
select pg_get_viewdef('tt14v', true);
@@ -1653,6 +1692,45 @@ select * from tt14v;
16531692
ERROR: attribute 4 of type record has wrong type
16541693
DETAIL: Table has type integer, but query expects text.
16551694
rollback;
1695+
drop view tt14v;
1696+
create view tt14v as select t.f1, t.f4 from tt14f() t;
1697+
select pg_get_viewdef('tt14v', true);
1698+
pg_get_viewdef
1699+
--------------------------------
1700+
SELECT t.f1, +
1701+
t.f4 +
1702+
FROM tt14f() t(f1, f3, f4);
1703+
(1 row)
1704+
1705+
select * from tt14v;
1706+
f1 | f4
1707+
-----+----
1708+
foo | 42
1709+
(1 row)
1710+
1711+
alter table tt14t drop column f3; -- ok
1712+
select pg_get_viewdef('tt14v', true);
1713+
pg_get_viewdef
1714+
----------------------------
1715+
SELECT t.f1, +
1716+
t.f4 +
1717+
FROM tt14f() t(f1, f4);
1718+
(1 row)
1719+
1720+
explain (verbose, costs off) select * from tt14v;
1721+
QUERY PLAN
1722+
----------------------------------------
1723+
Function Scan on testviewschm2.tt14f t
1724+
Output: t.f1, t.f4
1725+
Function Call: tt14f()
1726+
(3 rows)
1727+
1728+
select * from tt14v;
1729+
f1 | f4
1730+
-----+----
1731+
foo | 42
1732+
(1 row)
1733+
16561734
-- check display of whole-row variables in some corner cases
16571735
create type nestedcomposite as (x int8_tbl);
16581736
create view tt15v as select row(i)::nestedcomposite from int8_tbl i;

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,15 +2247,55 @@ select * from usersview;
22472247
id2 | 2 | email2 | 12 | t | 11 | 2
22482248
(2 rows)
22492249

2250+
alter table users drop column moredrop; -- fail, view has reference
2251+
ERROR: cannot drop column moredrop of table users because other objects depend on it
2252+
DETAIL: view usersview depends on column moredrop of table users
2253+
HINT: Use DROP ... CASCADE to drop the dependent objects too.
2254+
-- We used to have a bug that would allow the above to succeed, posing
2255+
-- hazards for later execution of the view. Check that the internal
2256+
-- defenses for those hazards haven't bit-rotted, in case some other
2257+
-- bug with similar symptoms emerges.
22502258
begin;
2259+
-- destroy the dependency entry that prevents the DROP:
2260+
delete from pg_depend where
2261+
objid = (select oid from pg_rewrite
2262+
where ev_class = 'usersview'::regclass and rulename = '_RETURN')
2263+
and refobjsubid = 5
2264+
returning pg_describe_object(classid, objid, objsubid) as obj,
2265+
pg_describe_object(refclassid, refobjid, refobjsubid) as ref,
2266+
deptype;
2267+
obj | ref | deptype
2268+
--------------------------------+--------------------------------+---------
2269+
rule _RETURN on view usersview | column moredrop of table users | n
2270+
(1 row)
2271+
22512272
alter table users drop column moredrop;
22522273
select * from usersview; -- expect clean failure
22532274
ERROR: attribute 5 of type record has been dropped
22542275
rollback;
2276+
alter table users alter column seq type numeric; -- fail, view has reference
2277+
ERROR: cannot alter type of a column used by a view or rule
2278+
DETAIL: rule _RETURN on view usersview depends on column "seq"
2279+
-- likewise, check we don't crash if the dependency goes wrong
2280+
begin;
2281+
-- destroy the dependency entry that prevents the ALTER:
2282+
delete from pg_depend where
2283+
objid = (select oid from pg_rewrite
2284+
where ev_class = 'usersview'::regclass and rulename = '_RETURN')
2285+
and refobjsubid = 2
2286+
returning pg_describe_object(classid, objid, objsubid) as obj,
2287+
pg_describe_object(refclassid, refobjid, refobjsubid) as ref,
2288+
deptype;
2289+
obj | ref | deptype
2290+
--------------------------------+---------------------------+---------
2291+
rule _RETURN on view usersview | column seq of table users | n
2292+
(1 row)
2293+
22552294
alter table users alter column seq type numeric;
22562295
select * from usersview; -- expect clean failure
22572296
ERROR: attribute 2 of type record has wrong type
22582297
DETAIL: Table has type numeric, but query expects integer.
2298+
rollback;
22592299
drop view usersview;
22602300
drop function get_first_user();
22612301
drop function get_users();

‎src/test/regress/sql/create_view.sql

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,24 @@ create view tt14v as select t.* from tt14f() t;
575575
select pg_get_viewdef('tt14v', true);
576576
select*from tt14v;
577577

578+
altertable tt14t drop column f3;-- fail, view has explicit reference to f3
579+
580+
-- We used to have a bug that would allow the above to succeed, posing
581+
-- hazards for later execution of the view. Check that the internal
582+
-- defenses for those hazards haven't bit-rotted, in case some other
583+
-- bug with similar symptoms emerges.
578584
begin;
579585

580-
-- this perhaps should be rejected, but it isn't:
586+
-- destroy the dependency entry that prevents the DROP:
587+
deletefrom pg_dependwhere
588+
objid= (selectoidfrom pg_rewrite
589+
where ev_class='tt14v'::regclassand rulename='_RETURN')
590+
and refobjsubid=3
591+
returning pg_describe_object(classid, objid, objsubid)as obj,
592+
pg_describe_object(refclassid, refobjid, refobjsubid)as ref,
593+
deptype;
594+
595+
-- this will now succeed:
581596
altertable tt14t drop column f3;
582597

583598
-- column f3 is still in the view, sort of ...
@@ -590,9 +605,22 @@ select * from tt14v;
590605

591606
rollback;
592607

608+
-- likewise, altering a referenced column's type is prohibited ...
609+
altertable tt14t alter column f4 typeinteger using f4::integer;-- fail
610+
611+
-- ... but some bug might let it happen, so check defenses
593612
begin;
594613

595-
-- this perhaps should be rejected, but it isn't:
614+
-- destroy the dependency entry that prevents the ALTER:
615+
deletefrom pg_dependwhere
616+
objid= (selectoidfrom pg_rewrite
617+
where ev_class='tt14v'::regclassand rulename='_RETURN')
618+
and refobjsubid=4
619+
returning pg_describe_object(classid, objid, objsubid)as obj,
620+
pg_describe_object(refclassid, refobjid, refobjsubid)as ref,
621+
deptype;
622+
623+
-- this will now succeed:
596624
altertable tt14t alter column f4 typeinteger using f4::integer;
597625

598626
-- f4 is still in the view ...
@@ -603,6 +631,19 @@ select * from tt14v;
603631

604632
rollback;
605633

634+
dropview tt14v;
635+
636+
createviewtt14vasselectt.f1,t.f4from tt14f() t;
637+
638+
select pg_get_viewdef('tt14v', true);
639+
select*from tt14v;
640+
641+
altertable tt14t drop column f3;-- ok
642+
643+
select pg_get_viewdef('tt14v', true);
644+
explain (verbose, costs off)select*from tt14v;
645+
select*from tt14v;
646+
606647
-- check display of whole-row variables in some corner cases
607648

608649
createtypenestedcompositeas (x int8_tbl);

‎src/test/regress/sql/rangefuncs.sql

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,12 +682,45 @@ SELECT * FROM ROWS FROM(get_users(), generate_series(10,11)) WITH ORDINALITY;
682682
select*from usersview;
683683
altertable users add column junktext;
684684
select*from usersview;
685+
686+
altertable users drop column moredrop;-- fail, view has reference
687+
688+
-- We used to have a bug that would allow the above to succeed, posing
689+
-- hazards for later execution of the view. Check that the internal
690+
-- defenses for those hazards haven't bit-rotted, in case some other
691+
-- bug with similar symptoms emerges.
685692
begin;
693+
694+
-- destroy the dependency entry that prevents the DROP:
695+
deletefrom pg_dependwhere
696+
objid= (selectoidfrom pg_rewrite
697+
where ev_class='usersview'::regclassand rulename='_RETURN')
698+
and refobjsubid=5
699+
returning pg_describe_object(classid, objid, objsubid)as obj,
700+
pg_describe_object(refclassid, refobjid, refobjsubid)as ref,
701+
deptype;
702+
686703
altertable users drop column moredrop;
687704
select*from usersview;-- expect clean failure
688705
rollback;
706+
707+
altertable users alter column seq typenumeric;-- fail, view has reference
708+
709+
-- likewise, check we don't crash if the dependency goes wrong
710+
begin;
711+
712+
-- destroy the dependency entry that prevents the ALTER:
713+
deletefrom pg_dependwhere
714+
objid= (selectoidfrom pg_rewrite
715+
where ev_class='usersview'::regclassand rulename='_RETURN')
716+
and refobjsubid=2
717+
returning pg_describe_object(classid, objid, objsubid)as obj,
718+
pg_describe_object(refclassid, refobjid, refobjsubid)as ref,
719+
deptype;
720+
689721
altertable users alter column seq typenumeric;
690722
select*from usersview;-- expect clean failure
723+
rollback;
691724

692725
dropview usersview;
693726
dropfunction get_first_user();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp