From 2523928b285b06242e0c669fadfc76d73bafdd66 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 15 Feb 2022 12:57:44 -0500 Subject: [PATCH] Reject change of output-column collation in CREATE OR REPLACE VIEW. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 | 20 +++++++++++-- src/test/regress/expected/create_view.out | 34 ++++++++++++++--------- src/test/regress/sql/create_view.sql | 25 +++++++++++------ 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index e183ab097c4..459e9821d08 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -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)))); } /* diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out index ca1833dc66d..ae7c04353cf 100644 --- a/src/test/regress/expected/create_view.out +++ b/src/test/regress/expected/create_view.out @@ -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 diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql index 6bb5b8df5e0..829f3ddbe68 100644 --- a/src/test/regress/sql/create_view.sql +++ b/src/test/regress/sql/create_view.sql @@ -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;