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

Commit9b35ddc

Browse files
committed
Partial fix for dropped columns in functions returning composite.
When a view has a function-returning-composite in FROM, and there aresome dropped columns in the underlying composite type, ruleutils.cprinted junk in the column alias list for the reconstructed FROM entry.Before 9.3, this was prevented by doing get_rte_attribute_is_droppedtests while printing the column alias list; but that solution is notcurrently available to us for reasons I'll explain below. Instead,check for empty-string entries in the alias list, which can only existif that column position had been dropped at the time the view was made.(The parser fills in empty strings to preserve the invariant that thealiases correspond to physical column positions.)While this is sufficient to handle the case of columns dropped beforethe view was made, we have still got issues with columns dropped afterthe view was made. In particular, the view could contain Vars thatexplicitly reference such columns! The dependency machinery reallyought to refuse the column drop attempt in such cases, as it would dowhen trying to drop a table column that's explicitly referenced inviews. However, we currently neglect to store dependencies on columnsof composite types, and fixing that is likely to be too big to beback-patchable (not to mention that existing views in existing databaseswould not have the needed pg_depend entries anyway). So I'll leave thatfor a separate patch.Pre-9.3, ruleutils would print such Vars normally (with their originalcolumn names) even though it suppressed their entries in the RTE'scolumn alias list. This is certainly bogus, since the printed viewdefinition would fail to reload, but at least it didn't crash. However,as of 9.3 the printed column alias list is tightly tied to the namesprinted for Vars; so we can't treat columns as dropped for one purposeand not dropped for the other. This is why we can't just put back theget_rte_attribute_is_dropped test: it results in an assertion failureif the view in fact contains any Vars referencing the dropped column.Once we've got dependencies preventing such cases, we'll probably wantto do it that way instead of relying on the empty-string test used here.This fix turned up a very ancient bug in outfuncs/readfuncs, namelythat T_String nodes containing empty strings were not dumped/reloadedcorrectly: the node was printed as "<>" which is read as a stringvalue of <>. Since (per SQL) we disallow empty-string identifiers,such nodes don't occur normally, which is why we'd not noticed.(Such nodes aren't used for literal constants, just identifiers.)Per report from Marc Schablewski. Back-patch to 9.3 which is wherethe rule printing behavior changed. The dangling-variable case isbroken all the way back, but that's not what his complaint is about.
1 parent85f9573 commit9b35ddc

File tree

4 files changed

+103
-2
lines changed

4 files changed

+103
-2
lines changed

‎src/backend/nodes/outfuncs.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2505,8 +2505,14 @@ _outValue(StringInfo str, const Value *value)
25052505
appendStringInfoString(str,value->val.str);
25062506
break;
25072507
caseT_String:
2508+
2509+
/*
2510+
* We use _outToken to provide escaping of the string's content,
2511+
* but we don't want it to do anything with an empty string.
2512+
*/
25082513
appendStringInfoChar(str,'"');
2509-
_outToken(str,value->val.str);
2514+
if (value->val.str[0]!='\0')
2515+
_outToken(str,value->val.str);
25102516
appendStringInfoChar(str,'"');
25112517
break;
25122518
caseT_BitString:

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3086,7 +3086,16 @@ set_relation_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
30863086
i=0;
30873087
foreach(lc,rte->eref->colnames)
30883088
{
3089-
real_colnames[i]=strVal(lfirst(lc));
3089+
/*
3090+
* If the column name shown in eref is an empty string, then it's
3091+
* a column that was dropped at the time of parsing the query, so
3092+
* treat it as dropped.
3093+
*/
3094+
char*cname=strVal(lfirst(lc));
3095+
3096+
if (cname[0]=='\0')
3097+
cname=NULL;
3098+
real_colnames[i]=cname;
30903099
i++;
30913100
}
30923101
}

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,58 @@ select pg_get_viewdef('vv6', true);
13321332
JOIN tt13 USING (z);
13331333
(1 row)
13341334

1335+
--
1336+
-- Check some cases involving dropped columns in a function's rowtype result
1337+
--
1338+
create table tt14t (f1 text, f2 text, f3 text, f4 text);
1339+
insert into tt14t values('foo', 'bar', 'baz', 'quux');
1340+
alter table tt14t drop column f2;
1341+
create function tt14f() returns setof tt14t as
1342+
$$
1343+
declare
1344+
rec1 record;
1345+
begin
1346+
for rec1 in select * from tt14t
1347+
loop
1348+
return next rec1;
1349+
end loop;
1350+
end;
1351+
$$
1352+
language plpgsql;
1353+
create view tt14v as select t.* from tt14f() t;
1354+
select pg_get_viewdef('tt14v', true);
1355+
pg_get_viewdef
1356+
--------------------------------
1357+
SELECT t.f1, +
1358+
t.f3, +
1359+
t.f4 +
1360+
FROM tt14f() t(f1, f3, f4);
1361+
(1 row)
1362+
1363+
select * from tt14v;
1364+
f1 | f3 | f4
1365+
-----+-----+------
1366+
foo | baz | quux
1367+
(1 row)
1368+
1369+
-- this perhaps should be rejected, but it isn't:
1370+
alter table tt14t drop column f3;
1371+
-- f3 is still in the view but will read as nulls
1372+
select pg_get_viewdef('tt14v', true);
1373+
pg_get_viewdef
1374+
--------------------------------
1375+
SELECT t.f1, +
1376+
t.f3, +
1377+
t.f4 +
1378+
FROM tt14f() t(f1, f3, f4);
1379+
(1 row)
1380+
1381+
select * from tt14v;
1382+
f1 | f3 | f4
1383+
-----+----+------
1384+
foo | | quux
1385+
(1 row)
1386+
13351387
-- clean up all the random objects we made above
13361388
set client_min_messages = warning;
13371389
DROP SCHEMA temp_view_test CASCADE;

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,40 @@ alter table tt11 add column z int;
435435

436436
select pg_get_viewdef('vv6', true);
437437

438+
--
439+
-- Check some cases involving dropped columns in a function's rowtype result
440+
--
441+
442+
createtablett14t (f1text, f2text, f3text, f4text);
443+
insert into tt14tvalues('foo','bar','baz','quux');
444+
445+
altertable tt14t drop column f2;
446+
447+
createfunctiontt14f() returns setof tt14tas
448+
$$
449+
declare
450+
rec1 record;
451+
begin
452+
for rec1inselect*from tt14t
453+
loop
454+
return next rec1;
455+
end loop;
456+
end;
457+
$$
458+
language plpgsql;
459+
460+
createviewtt14vasselect t.*from tt14f() t;
461+
462+
select pg_get_viewdef('tt14v', true);
463+
select*from tt14v;
464+
465+
-- this perhaps should be rejected, but it isn't:
466+
altertable tt14t drop column f3;
467+
468+
-- f3 is still in the view but will read as nulls
469+
select pg_get_viewdef('tt14v', true);
470+
select*from tt14v;
471+
438472
-- clean up all the random objects we made above
439473
set client_min_messages= warning;
440474
DROPSCHEMA temp_view_test CASCADE;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp