Skip to content

Commit a4e8680

Browse files
committed
When converting a table to a view, remove its system columns.
Views should not have any pg_attribute entries for system columns. However, we forgot to remove such entries when converting a table to a view. This could lead to crashes later on, if someone attempted to reference such a column, as reported by Kohei KaiGai. Patch in HEAD only. This bug has been there forever, but in the back branches we will have to defend against existing mis-converted views, so it doesn't seem worthwhile to change the conversion code too.
1 parent f4c4335 commit a4e8680

File tree

5 files changed

+88
-2
lines changed

5 files changed

+88
-2
lines changed

src/backend/catalog/heap.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,47 @@ DeleteAttributeTuples(Oid relid)
14341434
heap_close(attrel, RowExclusiveLock);
14351435
}
14361436

1437+
/*
1438+
* DeleteSystemAttributeTuples
1439+
*
1440+
* Remove pg_attribute rows for system columns of the given relid.
1441+
*
1442+
* Note: this is only used when converting a table to a view. Views don't
1443+
* have system columns, so we should remove them from pg_attribute.
1444+
*/
1445+
void
1446+
DeleteSystemAttributeTuples(Oid relid)
1447+
{
1448+
Relation attrel;
1449+
SysScanDesc scan;
1450+
ScanKeyData key[2];
1451+
HeapTuple atttup;
1452+
1453+
/* Grab an appropriate lock on the pg_attribute relation */
1454+
attrel = heap_open(AttributeRelationId, RowExclusiveLock);
1455+
1456+
/* Use the index to scan only system attributes of the target relation */
1457+
ScanKeyInit(&key[0],
1458+
Anum_pg_attribute_attrelid,
1459+
BTEqualStrategyNumber, F_OIDEQ,
1460+
ObjectIdGetDatum(relid));
1461+
ScanKeyInit(&key[1],
1462+
Anum_pg_attribute_attnum,
1463+
BTLessEqualStrategyNumber, F_INT2LE,
1464+
Int16GetDatum(0));
1465+
1466+
scan = systable_beginscan(attrel, AttributeRelidNumIndexId, true,
1467+
SnapshotNow, 2, key);
1468+
1469+
/* Delete all the matching tuples */
1470+
while ((atttup = systable_getnext(scan)) != NULL)
1471+
simple_heap_delete(attrel, &atttup->t_self);
1472+
1473+
/* Clean up after the scan */
1474+
systable_endscan(scan);
1475+
heap_close(attrel, RowExclusiveLock);
1476+
}
1477+
14371478
/*
14381479
* RemoveAttributeById
14391480
*

src/backend/rewrite/rewriteDefine.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "access/htup_details.h"
1919
#include "catalog/catalog.h"
2020
#include "catalog/dependency.h"
21+
#include "catalog/heap.h"
2122
#include "catalog/indexing.h"
2223
#include "catalog/namespace.h"
2324
#include "catalog/objectaccess.h"
@@ -510,13 +511,19 @@ DefineQueryRewrite(char *rulename,
510511
}
511512

512513
/*
513-
* IF the relation is becoming a view, delete the storage files associated
514-
* with it. NB: we had better have AccessExclusiveLock to do this ...
514+
* If the relation is becoming a view, delete the storage files associated
515+
* with it. Also, get rid of any system attribute entries in pg_attribute,
516+
* because a view shouldn't have any of those.
517+
*
518+
* NB: we had better have AccessExclusiveLock to do this ...
515519
*
516520
* XXX what about getting rid of its TOAST table? For now, we don't.
517521
*/
518522
if (RelisBecomingView)
523+
{
519524
RelationDropStorage(event_relation);
525+
DeleteSystemAttributeTuples(event_relid);
526+
}
520527

521528
/* Close rel, but keep lock till commit... */
522529
heap_close(event_relation, NoLock);

src/include/catalog/heap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ extern Node *cookDefault(ParseState *pstate,
107107

108108
extern void DeleteRelationTuple(Oid relid);
109109
extern void DeleteAttributeTuples(Oid relid);
110+
extern void DeleteSystemAttributeTuples(Oid relid);
110111
extern void RemoveAttributeById(Oid relid, AttrNumber attnum);
111112
extern void RemoveAttrDefault(Oid relid, AttrNumber attnum,
112113
DropBehavior behavior, bool complain, bool internal);

src/test/regress/expected/rules.out

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,28 @@ ERROR: cannot drop rule _RETURN on view fooview because view fooview requires i
14571457
HINT: You can drop view fooview instead.
14581458
drop view fooview;
14591459
--
1460+
-- test conversion of table to view (needed to load some pg_dump files)
1461+
--
1462+
create table fooview (x int, y text);
1463+
select xmin, * from fooview;
1464+
xmin | x | y
1465+
------+---+---
1466+
(0 rows)
1467+
1468+
create rule "_RETURN" as on select to fooview do instead
1469+
select 1 as x, 'aaa'::text as y;
1470+
select * from fooview;
1471+
x | y
1472+
---+-----
1473+
1 | aaa
1474+
(1 row)
1475+
1476+
select xmin, * from fooview; -- fail, views don't have such a column
1477+
ERROR: column "xmin" does not exist
1478+
LINE 1: select xmin, * from fooview;
1479+
^
1480+
drop view fooview;
1481+
--
14601482
-- check for planner problems with complex inherited UPDATES
14611483
--
14621484
create table id (id serial primary key, name text);

src/test/regress/sql/rules.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,21 @@ create view fooview as select 'foo'::text;
859859
drop rule "_RETURN" on fooview;
860860
drop view fooview;
861861

862+
--
863+
-- test conversion of table to view (needed to load some pg_dump files)
864+
--
865+
866+
create table fooview (x int, y text);
867+
select xmin, * from fooview;
868+
869+
create rule "_RETURN" as on select to fooview do instead
870+
select 1 as x, 'aaa'::text as y;
871+
872+
select * from fooview;
873+
select xmin, * from fooview; -- fail, views don't have such a column
874+
875+
drop view fooview;
876+
862877
--
863878
-- check for planner problems with complex inherited UPDATES
864879
--

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