Prevent parser from believing that views have system columns.
authorTom Lane <[email protected]>
Wed, 24 Oct 2012 18:54:17 +0000 (14:54 -0400)
committerTom Lane <[email protected]>
Wed, 24 Oct 2012 18:54:17 +0000 (14:54 -0400)
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.

This problem is corrected properly in HEAD (by removing the pg_attribute
entries during conversion), but in the back branches we need to defend
against existing mis-converted views.  This fix costs us an extra syscache
lookup per system column reference, which is annoying but probably not
really measurable in the big scheme of things.

src/backend/parser/parse_relation.c
src/test/regress/expected/rules.out
src/test/regress/sql/rules.sql

index 444934efa4dcf7aa8ec01c7d5d89732837c7095a..af02202d9580efe4d22219226de1bc9a90aee802 100644 (file)
@@ -383,11 +383,18 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
        attnum = specialAttNum(colname);
        if (attnum != InvalidAttrNumber)
        {
-           /* now check to see if column actually is defined */
+           /*
+            * Now check to see if column actually is defined.  Because of
+            * an ancient oversight in DefineQueryRewrite, it's possible that
+            * pg_attribute contains entries for system columns for a view,
+            * even though views should not have such --- so we also check
+            * the relkind.  This kluge will not be needed in 9.3 and later.
+            */
            if (SearchSysCacheExists(ATTNUM,
                                     ObjectIdGetDatum(rte->relid),
                                     Int16GetDatum(attnum),
-                                    0, 0))
+                                    0, 0) &&
+               get_rel_relkind(rte->relid) != RELKIND_VIEW)
            {
                result = (Node *) make_var(pstate, rte, attnum);
                /* Require read access */
index 3439642fe65aaded7fef76aa8e0188eb78731f06..2e5d0974dd5b14aeb24f8edc9ff33ff9d7d3590a 100644 (file)
@@ -1442,6 +1442,28 @@ insert into rule_and_refint_t3 values (1, 13, 11, 'row8');
 ERROR:  insert or update on table "rule_and_refint_t3" violates foreign key constraint "rule_and_refint_t3_id3a_fkey"
 DETAIL:  Key (id3a,id3b)=(1,13) is not present in table "rule_and_refint_t1".
 --
+-- test conversion of table to view (needed to load some pg_dump files)
+--
+create table fooview (x int, y text);
+select xmin, * from fooview;
+ xmin | x | y 
+------+---+---
+(0 rows)
+
+create rule "_RETURN" as on select to fooview do instead
+  select 1 as x, 'aaa'::text as y;
+select * from fooview;
+ x |  y  
+---+-----
+ 1 | aaa
+(1 row)
+
+select xmin, * from fooview;  -- fail, views don't have such a column
+ERROR:  column "xmin" does not exist
+LINE 1: select xmin, * from fooview;
+               ^
+drop view fooview;
+--
 -- check for planner problems with complex inherited UPDATES
 --
 create table id (id serial primary key, name text);
index e898336d92a27df3bdb70cd8b3391022abd5ea8d..428f92bf4f5d14856216b653791c45483f5af608 100644 (file)
@@ -851,6 +851,21 @@ create rule rule_and_refint_t3_ins as on insert to rule_and_refint_t3
 insert into rule_and_refint_t3 values (1, 11, 13, 'row7');
 insert into rule_and_refint_t3 values (1, 13, 11, 'row8');
 
+--
+-- test conversion of table to view (needed to load some pg_dump files)
+--
+
+create table fooview (x int, y text);
+select xmin, * from fooview;
+
+create rule "_RETURN" as on select to fooview do instead
+  select 1 as x, 'aaa'::text as y;
+
+select * from fooview;
+select xmin, * from fooview;  -- fail, views don't have such a column
+
+drop view fooview;
+
 --
 -- check for planner problems with complex inherited UPDATES
 --