Thread
Commits
-
Fix more bugs caused by adding columns to the end of a view.
- 99be6feec971 16.0 landed
- 76d2177fb693 15.3 landed
- 9f1e51b59673 14.8 landed
- 721626cb57c0 11.20 landed
- 695b34ab359d 13.11 landed
- 5a19da58eed2 12.15 landed
-
Fix crash when columns have been added to the end of a view.
- d5b760ecb5e1 11.0 cited
-
BUG #17811: Replacing an underlying view breaks OLD/NEW tuple when accessing it via upper-level view
The Post Office <noreply@postgresql.org> — 2023-02-27T20:00:03Z
The following bug has been logged on the website: Bug reference: 17811 Logged by: Alexander Lakhin Email address: exclusion@gmail.com PostgreSQL version: 15.2 Operating system: Ubuntu 22.04 Description: I've discovered an issue with replacing a view when there is another updatable view defined on top of it and the new underlying view has more columns than the previous one. First example with triggers: CREATE TABLE t (id int, f1 text); CREATE VIEW v1 AS SELECT id FROM t; CREATE VIEW v2 AS SELECT * FROM v1; CREATE OR REPLACE VIEW v1 AS SELECT * FROM t; CREATE FUNCTION v1_trig_fn() RETURNS trigger AS $$ BEGIN RAISE NOTICE 'old.id: %, old.f1: %', old.id, old.f1; UPDATE t SET id=new.id WHERE id=old.id; RETURN new; END; $$ LANGUAGE plpgsql; CREATE TRIGGER v1_upd_trig INSTEAD OF UPDATE ON v1 FOR EACH ROW EXECUTE FUNCTION v1_trig_fn(); INSERT INTO t VALUES (1, 11), (2, 22); SELECT * FROM t; UPDATE v2 SET id = 3 WHERE id = 2; SELECT * FROM t; id | f1 ----+---- 1 | 11 2 | 22 (2 rows) NOTICE: old.id: 2, old.f1: <NULL> -- ??? UPDATE 1 id | f1 ----+---- 1 | 11 3 | 22 (2 rows) but if new v1 defined with security_barrier: CREATE OR REPLACE VIEW v1 WITH (security_barrier = true) AS SELECT * FROM t; ... NOTICE: old.id: 2, old.f1: 22, old.f2: 222 -- OK but on master (after 47bb9db75) ... NOTICE: old.id: 2, old.f1: 22, old.f2: 222 WARNING: problem in alloc set MessageContext: req size > alloc size for chunk 0x62900003ccb0 in block 0x62900003c200 WARNING: problem in alloc set MessageContext: req size > alloc size for chunk 0x62900003ccb0 in block 0x62900003c200 (I've seen also runtime errors detected by asan.) Second example with rules (REL_15_STABLE without asserts): CREATE TABLE t(id int, f1 int, f2 int, f3 int, f4 int); CREATE TABLE tc(id int, f int); CREATE VIEW v1 AS SELECT 1 AS id; CREATE VIEW v2 AS SELECT * FROM v1; CREATE OR REPLACE VIEW v1 WITH (security_barrier = true) AS SELECT * FROM t; CREATE RULE v1_upd_rule AS ON UPDATE TO v1 DO INSTEAD (INSERT INTO tc VALUES (NEW.id, NEW.f1); UPDATE t SET id = NEW.id WHERE id = OLD.id;); INSERT INTO t VALUES (1, 11, 111, 1111, 11111), (2, 22, 222, 2222, 22222); SELECT * FROM t; SELECT * FROM v2; UPDATE v2 SET id = 3 WHERE id = 2; SELECT * FROM t; SELECT * FROM tc; id ---- 1 2 (2 rows) server closed the connection unexpectedly ... Program terminated with signal SIGSEGV, Segmentation fault. #0 0x0000555b19cd22b6 in bms_add_members (a=0x8, b=b@entry=0x555b1a645990) at bitmapset.c:808 808 if (a->nwords < b->nwords) (gdb) bt #0 0x0000555b19cd22b6 in bms_add_members (a=0x8, b=b@entry=0x555b1a645990) at bitmapset.c:808 #1 0x0000555b19d29273 in add_vars_to_targetlist (root=0x555b1a645088, vars=0x555b1a645940, where_needed=0x555b1a645990, create_new_ph=true) at initsplan.c:259 #2 0x0000555b19d2931d in build_base_rel_tlists (root=0x555b1a645088, final_tlist=<optimized out>) at initsplan.c:192 #3 0x0000555b19d2be26 in query_planner (root=root@entry=0x555b1a645088, qp_callback=qp_callback@entry=0x555b19d2c430 <standard_qp_callback>, qp_extra=qp_extra@entry=0x7fffd186cd10) at planmain.c:178 ... But with: CREATE RULE v1_upd_rule AS ON UPDATE TO v1 DO INSTEAD (INSERT INTO tc VALUES (NEW.id, NEW.f3); UPDATE t SET id = NEW.id WHERE id = OLD.id;); ... id ---- 1 2 (2 rows) UPDATE 1 id | f1 | f2 | f3 | f4 ----+----+-----+------+------- 1 | 11 | 111 | 1111 | 11111 3 | 22 | 222 | 2222 | 22222 (2 rows) id | f ----+------ 3 | 2222 (1 row) (Maybe it succeeded accidentally.) REL_15_STABLE with asserts: TRAP: FailedAssertion("attno >= rel->min_attr && attno <= rel->max_attr", File: "initsplan.c", Line: 249, PID: 266170) Interestingly enough, but replacing an underlying view with incompatible fields is prohibited (thanks to a check in checkViewTupleDesc()): CREATE VIEW v1 AS SELECT 1::text AS id; CREATE VIEW v2 AS SELECT * FROM v1; CREATE OR REPLACE VIEW v1 WITH (security_barrier = true) AS SELECT * FROM t; ERROR: cannot change data type of view column "id" from text to integer Just as decreasing of a number of columns: CREATE VIEW v1 AS SELECT 1 AS id, 11 AS f1, 111 AS f2, 1111 AS f3, 11111 AS f4, 111111 AS f5; CREATE VIEW v2 AS SELECT * FROM v1; CREATE OR REPLACE VIEW v1 WITH (security_barrier = true) AS SELECT * FROM t; ERROR: cannot drop columns from view Maybe replacing a view with increasing number of columns should be prohibited too? -
Re: BUG #17811: Replacing an underlying view breaks OLD/NEW tuple when accessing it via upper-level view
Tom Lane <tgl@sss.pgh.pa.us> — 2023-02-27T21:35:49Z
PG Bug reporting form <noreply@postgresql.org> writes: > Maybe replacing a view with increasing number of columns should be > prohibited too? It's intentional that we allow that case; it'd be sad if we have to remove the feature because of bugs. regards, tom lane
-
Re: BUG #17811: Replacing an underlying view breaks OLD/NEW tuple when accessing it via upper-level view
Tom Lane <tgl@sss.pgh.pa.us> — 2023-03-07T18:43:05Z
PG Bug reporting form <noreply@postgresql.org> writes: > I've discovered an issue with replacing a view when there is another > updatable view defined on top of it and the new underlying view has > more columns than the previous one. I've looked into this a bit more, and both of these symptoms reduce to the same thing: after we've plugged the modified view's query into the upper query, we have an RTE_SUBQUERY RTE whose eref->colnames list is shorter than the number of columns actually available from the subquery. This breaks assorted code that is expecting that it can use list_length(eref->colnames) as a quick guide to the number of output columns. We have seen this before (bug #14876, commit d5b760ecb) and at the time our response was to patch up the code making such an assumption. But you've just demonstrated at least two other places with the same issue, so now I'm feeling that we'd be best advised to fix it centrally in the rewriter code that plugs in the view definition. The attached fix causes a change in the regression test output for bug #14876's test case, but AFAICS the change is a strict improvement: we get something sane, not a NULL, for the added column. I'm not sure whether to change the code added to expandRTE in d5b760ecb or leave it be. We could make it into elog(ERROR) now, perhaps. regards, tom lane
-
Re: BUG #17811: Replacing an underlying view breaks OLD/NEW tuple when accessing it via upper-level view
Alexander Law <exclusion@gmail.com> — 2023-03-08T06:00:00Z
07.03.2023 21:43, Tom Lane wrote: > I've looked into this a bit more, and both of these symptoms reduce > to the same thing: after we've plugged the modified view's query > into the upper query, we have an RTE_SUBQUERY RTE whose eref->colnames > list is shorter than the number of columns actually available from the > subquery. This breaks assorted code that is expecting that it can > use list_length(eref->colnames) as a quick guide to the number of > output columns. Thanks for the fix! I've tested all my cases on REL_15_STABLE, master and found no anomalies in this area. Best regards, Alexander