Reject change of output-column collation in CREATE OR REPLACE VIEW.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 15 Feb 2022 17:57:44 +0000 (12:57 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 15 Feb 2022 17:57:44 +0000 (12:57 -0500)
checkViewTupleDesc() didn't get the memo that it should verify
same attcollation along with same type/typmod.  (A quick scan
did not find other similar oversights.)

Per bug #17404 from Pierre-Aurélien Georges.  On another day
I might've back-patched this, but today I'm feeling paranoid
about unnecessary behavioral changes in back branches.

Discussion: https://postgr.es/m/17404-8a4a270ef30a6709@postgresql.org

src/backend/commands/view.c
src/test/regress/expected/create_view.out
src/test/regress/sql/create_view.sql

index e183ab097c44cda951696e1b2f2250118344c72c..459e9821d08142fb66f901e554c6a894b528d3bf 100644 (file)
@@ -282,7 +282,12 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
                            NameStr(oldattr->attname),
                            NameStr(newattr->attname)),
                     errhint("Use ALTER VIEW ... RENAME COLUMN ... to change name of view column instead.")));
-       /* XXX would it be safe to allow atttypmod to change?  Not sure */
+
+       /*
+        * We cannot allow type, typmod, or collation to change, since these
+        * properties may be embedded in Vars of other views/rules referencing
+        * this one.  Other column attributes can be ignored.
+        */
        if (newattr->atttypid != oldattr->atttypid ||
            newattr->atttypmod != oldattr->atttypmod)
            ereport(ERROR,
@@ -293,7 +298,18 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
                                                     oldattr->atttypmod),
                            format_type_with_typemod(newattr->atttypid,
                                                     newattr->atttypmod))));
-       /* We can ignore the remaining attributes of an attribute... */
+
+       /*
+        * At this point, attcollations should be both valid or both invalid,
+        * so applying get_collation_name unconditionally should be fine.
+        */
+       if (newattr->attcollation != oldattr->attcollation)
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+                    errmsg("cannot change collation of view column \"%s\" from \"%s\" to \"%s\"",
+                           NameStr(oldattr->attname),
+                           get_collation_name(oldattr->attcollation),
+                           get_collation_name(newattr->attcollation))));
    }
 
    /*
index ca1833dc66dccde4e17c4a27bc872bfbbc279ed3..ae7c04353cf2258b841d342c57526d64d26b10f7 100644 (file)
@@ -54,27 +54,27 @@ CREATE VIEW key_dependent_view_no_cols AS
 --
 -- CREATE OR REPLACE VIEW
 --
-CREATE TABLE viewtest_tbl (a int, b int);
+CREATE TABLE viewtest_tbl (a int, b int, c numeric(10,1), d text COLLATE "C");
 COPY viewtest_tbl FROM stdin;
 CREATE OR REPLACE VIEW viewtest AS
    SELECT * FROM viewtest_tbl;
 CREATE OR REPLACE VIEW viewtest AS
    SELECT * FROM viewtest_tbl WHERE a > 10;
 SELECT * FROM viewtest;
- a  | b  
-----+----
- 15 | 20
- 20 | 25
+ a  | b  |  c  |   d   
+----+----+-----+-------
+ 15 | 20 | 3.3 | xyzz
+ 20 | 25 | 4.4 | xyzzy
 (2 rows)
 
 CREATE OR REPLACE VIEW viewtest AS
-   SELECT a, b FROM viewtest_tbl WHERE a > 5 ORDER BY b DESC;
+   SELECT a, b, c, d FROM viewtest_tbl WHERE a > 5 ORDER BY b DESC;
 SELECT * FROM viewtest;
- a  | b  
-----+----
- 20 | 25
- 15 | 20
- 10 | 15
+ a  | b  |  c  |   d   
+----+----+-----+-------
+ 20 | 25 | 4.4 | xyzzy
+ 15 | 20 | 3.3 | xyzz
+ 10 | 15 | 2.2 | xyz
 (3 rows)
 
 -- should fail
@@ -88,11 +88,19 @@ ERROR:  cannot change name of view column "a" to "?column?"
 HINT:  Use ALTER VIEW ... RENAME COLUMN ... to change name of view column instead.
 -- should fail
 CREATE OR REPLACE VIEW viewtest AS
-   SELECT a, b::numeric FROM viewtest_tbl;
+   SELECT a, b::numeric, c, d FROM viewtest_tbl;
 ERROR:  cannot change data type of view column "b" from integer to numeric
+-- should fail
+CREATE OR REPLACE VIEW viewtest AS
+   SELECT a, b, c::numeric(10,2), d FROM viewtest_tbl;
+ERROR:  cannot change data type of view column "c" from numeric(10,1) to numeric(10,2)
+-- should fail
+CREATE OR REPLACE VIEW viewtest AS
+   SELECT a, b, c, d COLLATE "POSIX" FROM viewtest_tbl;
+ERROR:  cannot change collation of view column "d" from "C" to "POSIX"
 -- should work
 CREATE OR REPLACE VIEW viewtest AS
-   SELECT a, b, 0 AS c FROM viewtest_tbl;
+   SELECT a, b, c, d, 0 AS e FROM viewtest_tbl;
 DROP VIEW viewtest;
 DROP TABLE viewtest_tbl;
 -- tests for temporary views
index 6bb5b8df5e08a05a1f004f1b2285e08034c560be..829f3ddbe68da5caea41f8b3eb2c621a1ad9c175 100644 (file)
@@ -67,12 +67,13 @@ CREATE VIEW key_dependent_view_no_cols AS
 -- CREATE OR REPLACE VIEW
 --
 
-CREATE TABLE viewtest_tbl (a int, b int);
+CREATE TABLE viewtest_tbl (a int, b int, c numeric(10,1), d text COLLATE "C");
+
 COPY viewtest_tbl FROM stdin;
-5  10
-10 15
-15 20
-20 25
+5  10  1.1 xy
+10 15  2.2 xyz
+15 20  3.3 xyzz
+20 25  4.4 xyzzy
 \.
 
 CREATE OR REPLACE VIEW viewtest AS
@@ -84,7 +85,7 @@ CREATE OR REPLACE VIEW viewtest AS
 SELECT * FROM viewtest;
 
 CREATE OR REPLACE VIEW viewtest AS
-   SELECT a, b FROM viewtest_tbl WHERE a > 5 ORDER BY b DESC;
+   SELECT a, b, c, d FROM viewtest_tbl WHERE a > 5 ORDER BY b DESC;
 
 SELECT * FROM viewtest;
 
@@ -98,11 +99,19 @@ CREATE OR REPLACE VIEW viewtest AS
 
 -- should fail
 CREATE OR REPLACE VIEW viewtest AS
-   SELECT a, b::numeric FROM viewtest_tbl;
+   SELECT a, b::numeric, c, d FROM viewtest_tbl;
+
+-- should fail
+CREATE OR REPLACE VIEW viewtest AS
+   SELECT a, b, c::numeric(10,2), d FROM viewtest_tbl;
+
+-- should fail
+CREATE OR REPLACE VIEW viewtest AS
+   SELECT a, b, c, d COLLATE "POSIX" FROM viewtest_tbl;
 
 -- should work
 CREATE OR REPLACE VIEW viewtest AS
-   SELECT a, b, 0 AS c FROM viewtest_tbl;
+   SELECT a, b, c, d, 0 AS e FROM viewtest_tbl;
 
 DROP VIEW viewtest;
 DROP TABLE viewtest_tbl;