mirror of
https://github.com/postgres/postgres.git
synced 2025-09-03 15:22:11 +03:00
Yet further fixes for multi-row VALUES lists for updatable views.
DEFAULT markers appearing in an INSERT on an updatable view
could be mis-processed if they were in a multi-row VALUES clause.
This would lead to strange errors such as "cache lookup failed
for type NNNN", or in older branches even to crashes.
The cause is that commit 41531e42d
tried to re-use rewriteValuesRTE()
to remove any SetToDefault nodes (that hadn't previously been replaced
by the view's own default values) appearing in "product" queries,
that is DO ALSO queries. That's fundamentally wrong because the
DO ALSO queries might not even be INSERTs; and even if they are,
their targetlists don't necessarily match the view's column list,
so that almost all the logic in rewriteValuesRTE() is inapplicable.
What we want is a narrow focus on replacing any such nodes with NULL
constants. (That is, in this context we are interpreting the defaults
as being strictly those of the view itself; and we already replaced
any that aren't NULL.) We could add still more !force_nulls tests
to further lobotomize rewriteValuesRTE(); but it seems cleaner to
split out this case to a new function, restoring rewriteValuesRTE()
to the charter it had before.
Per bug #17633 from jiye_sw. Patch by me, but thanks to
Richard Guo and Japin Li for initial investigation.
Back-patch to all supported branches, as the previous fix was.
Discussion: https://postgr.es/m/17633-98cc85e1fa91e905@postgresql.org
This commit is contained in:
@@ -433,8 +433,30 @@ EXPLAIN (costs off) DELETE FROM rw_view1 WHERE a=5;
|
||||
Index Cond: ((a > 0) AND (a = 5))
|
||||
(3 rows)
|
||||
|
||||
-- it's still updatable if we add a DO ALSO rule
|
||||
CREATE TABLE base_tbl_hist(ts timestamptz default now(), a int, b text);
|
||||
CREATE RULE base_tbl_log AS ON INSERT TO rw_view1 DO ALSO
|
||||
INSERT INTO base_tbl_hist(a,b) VALUES(new.a, new.b);
|
||||
SELECT table_name, is_updatable, is_insertable_into
|
||||
FROM information_schema.views
|
||||
WHERE table_name = 'rw_view1';
|
||||
table_name | is_updatable | is_insertable_into
|
||||
------------+--------------+--------------------
|
||||
rw_view1 | YES | YES
|
||||
(1 row)
|
||||
|
||||
-- Check behavior with DEFAULTs (bug #17633)
|
||||
INSERT INTO rw_view1 VALUES (9, DEFAULT), (10, DEFAULT);
|
||||
SELECT a, b FROM base_tbl_hist;
|
||||
a | b
|
||||
----+---
|
||||
9 |
|
||||
10 |
|
||||
(2 rows)
|
||||
|
||||
DROP TABLE base_tbl CASCADE;
|
||||
NOTICE: drop cascades to view rw_view1
|
||||
DROP TABLE base_tbl_hist;
|
||||
-- view on top of view
|
||||
CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified');
|
||||
INSERT INTO base_tbl SELECT i, 'Row ' || i FROM generate_series(-2, 2) g(i);
|
||||
|
@@ -148,7 +148,24 @@ SELECT * FROM base_tbl;
|
||||
EXPLAIN (costs off) UPDATE rw_view1 SET a=6 WHERE a=5;
|
||||
EXPLAIN (costs off) DELETE FROM rw_view1 WHERE a=5;
|
||||
|
||||
-- it's still updatable if we add a DO ALSO rule
|
||||
|
||||
CREATE TABLE base_tbl_hist(ts timestamptz default now(), a int, b text);
|
||||
|
||||
CREATE RULE base_tbl_log AS ON INSERT TO rw_view1 DO ALSO
|
||||
INSERT INTO base_tbl_hist(a,b) VALUES(new.a, new.b);
|
||||
|
||||
SELECT table_name, is_updatable, is_insertable_into
|
||||
FROM information_schema.views
|
||||
WHERE table_name = 'rw_view1';
|
||||
|
||||
-- Check behavior with DEFAULTs (bug #17633)
|
||||
|
||||
INSERT INTO rw_view1 VALUES (9, DEFAULT), (10, DEFAULT);
|
||||
SELECT a, b FROM base_tbl_hist;
|
||||
|
||||
DROP TABLE base_tbl CASCADE;
|
||||
DROP TABLE base_tbl_hist;
|
||||
|
||||
-- view on top of view
|
||||
|
||||
|
Reference in New Issue
Block a user