Thread: I incrementally altered my database into a state where backups couldn't be restored.
I incrementally altered my database into a state where backups couldn't be restored.
From
"Adam Tomjack"
Date:
I was able to put my database into a state where I couldn't restore a backup without manually editing the backup file. I make backups like so: $pg_dump --disable-triggers -S postgres -U postgres dbname > dbname.sql I did an ALTER TABLE which added a column to a table. That table was used in a join in a view. After adding the column, the SELECT that is the body of my view would no longer work, even though the ALTER TABLE succeeded and the view continued to work. The problem was that when I would try to restore my database from a backup made after the ALTER TABLE, the statement that restored the view would fail. The error got lost in the output, and I didn't notice the problem until I tried to query the view on the restored database. Here's an example: -- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D /* DROP TABLE c CASCADE; DROP TABLE b CASCADE; DROP TABLE a CASCADE; */ CREATE TABLE a ( aid SERIAL PRIMARY KEY ); CREATE TABLE b ( bid SERIAL PRIMARY KEY, aid INTEGER REFERENCES a ); CREATE TABLE c ( cid SERIAL PRIMARY KEY, bid INTEGER REFERENCES b ); CREATE VIEW v_a_b_c AS=20 SELECT *=20 FROM b JOIN c USING (bid) JOIN a USING (aid) ; SELECT * FROM v_a_b_c; ALTER TABLE c ADD COLUMN aid INTEGER REFERENCES a; -- This will succeed: SELECT * FROM v_a_b_c; -- But, this will fail with=20 -- ERROR: common column name "aid" appears more than once in left table -- SQL state: 42702 SELECT *=20 FROM b JOIN c USING (bid) JOIN a USING (aid) -- It is now possible to make a backup with pg_dump that cannot be fully restored.=20=20 -- When restoring, this will fail: CREATE OR REPLACE VIEW v_a_b_c AS=20 SELECT *=20 FROM b JOIN c USING (bid) JOIN a USING (aid) ; -- A workaround is to hand-edit the backup file and fix the broken SELECT. -- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D I am not subscribed to this list. If you need clarification, please email me directly. Adam Tomjack Zuercher Technologies LLC 108 E. Missouri Ave. Suite 1 Pierre, SD 57501 (605) 224-4838
Re: I incrementally altered my database into a state where backups couldn't be restored.
From
Heikki Linnakangas
Date:
Adam Tomjack wrote: > I was able to put my database into a state where I couldn't restore a > backup without manually editing the backup file. I can't reproduce that on 8.1 or 8.2 or CVS HEAD. pg_dump produces this CREATE statement for the view: CREATE VIEW v_a_b_c AS SELECT b.aid, b.bid, c.cid FROM ((b JOIN c USING (bid)) JOIN a USING (aid)); Not the CREATE OR REPLACE with a SELECT * you posted. Which version of Postgres are you using? -- Heikki Linnakangas EnterpriseDB http://www.enterprisedb.com
Re: I incrementally altered my database into a state where backups couldn't be restored.
From
Gregory Stark
Date:
"Adam Tomjack" <adamtj@zuerchertech.com> writes: > -- This will succeed: > SELECT * FROM v_a_b_c; > > -- But, this will fail with > -- ERROR: common column name "aid" appears more than once in left table > -- SQL state: 42702 > SELECT * > FROM b > JOIN c USING (bid) > JOIN a USING (aid) > > -- It is now possible to make a backup with pg_dump that cannot be fully > restored. > -- When restoring, this will fail: > CREATE OR REPLACE VIEW v_a_b_c AS > SELECT * > FROM b > JOIN c USING (bid) > JOIN a USING (aid) > ; That does really suck. But I'm not sure what we can do about it. There's no SQL which is entirely equivalent to the resulting view. I think the closest you could get would be something like SELECT * FROM (SELECT bid,cid FROM b) AS b JOIN c USING (bid) JOIN a USING (aid) But it's not clear to me that we could generate that easily. AFAIK the information about which columns were in the table at the time the view was defined isn't readily available. And checking for conflicts might be hard since they could happen much higher up in the join tree. We can't just output the USING as an ON clause which would let pg_dump specify precisely which column to join against because ON doesn't merge the two columns. The resulting records would have two bid columns. -- Gregory Stark EnterpriseDB http://www.enterprisedb.com Ask me about EnterpriseDB's On-Demand Production Tuning
Re: I incrementally altered my database into a state where backups couldn't be restored.
From
Tom Lane
Date:
Gregory Stark <stark@enterprisedb.com> writes: > That does really suck. But I'm not sure what we can do about it. There's no > SQL which is entirely equivalent to the resulting view. If we were to do anything about it, I think it would have to be to forbid the original ALTER. But I don't see any good way to detect the situation, either. Consider also that an ALTER ... RENAME could create a similar failure, if the new column name conflicts with one in some other table that is joined against someplace. I think that the described behavior is actually pretty harmless: you get everything back except the broken view. So I'm not too unhappy saying that it's going to keep working that way. regards, tom lane
Re: I incrementally altered my database into a state where backups couldn't be restored.
From
Gregory Stark
Date:
"Tom Lane" <tgl@sss.pgh.pa.us> writes: > Gregory Stark <stark@enterprisedb.com> writes: >> That does really suck. But I'm not sure what we can do about it. There's no >> SQL which is entirely equivalent to the resulting view. > > If we were to do anything about it, I think it would have to be to > forbid the original ALTER. But I don't see any good way to detect > the situation, either. Hm, we could call pg_get_viewdef() on dependent views and then verify that the resulting view compiles without error. For bonus points we could verify that it produces the same parsed view and throw warning if it doesn't. That would give us a warning if you have a view with natural joins which changed meanings. I'm not sure it's worth that much extra work on every ALTER TABLE though. I suppose pg_dump() could have an option to check these things itself but by that point it's too late to do anything about it. -- Gregory Stark EnterpriseDB http://www.enterprisedb.com Ask me about EnterpriseDB's Slony Replication support!
Re: I incrementally altered my database into a state where backups couldn't be restored.
From
Heikki Linnakangas
Date:
Heikki Linnakangas wrote: > Adam Tomjack wrote: >> I was able to put my database into a state where I couldn't restore a >> backup without manually editing the backup file. > > I can't reproduce that on 8.1 or 8.2 or CVS HEAD. pg_dump produces this > CREATE statement for the view: > > CREATE VIEW v_a_b_c AS > SELECT b.aid, b.bid, c.cid FROM ((b JOIN c USING (bid)) JOIN a USING > (aid)); > > Not the CREATE OR REPLACE with a SELECT * you posted. Greg Stark pointed out that the above doesn't work either, though it's not the exact same output you posted. I don't see any feasible way to fix that, unfortunately. We'd need to rewrite view definition quite a bit behind the scenes. -- Heikki Linnakangas EnterpriseDB http://www.enterprisedb.com
Re: I incrementally altered my database into a state where backups couldn't be restored.
From
"Adam Tomjack"
Date:
> Which version of Postgres are you using? PostgreSQL 8.1.5 on i686-pc-mingw32, compiled by GCC gcc.exe (GCC) 3.4.2 (mingw-special) > I can't reproduce that on 8.1 or 8.2 or CVS HEAD.=20 > [...] > Not the CREATE OR REPLACE with a SELECT * you posted. I was lazy, I apologize. I typed the CREATE OR REPLACE myself. I get the same thing as Heikki from pg_dump. The point is that it breaks when restoring with psql[1] > I think that the described behavior is actually pretty harmless: Having been bitten by this, I must respectfully disagree. When I found the problem, I was copying a database over to a demonstration laptop for a show. I missed the error message when it scrolled past, so it seemed to work. Fortunately, I happened to check the area of my app that used the missing view, so I found it before trying to demo. Now that I know about it, I can fix my scripts to help me watch out for it. It's just one of those things I didn't think to test for until I ran into it. > Hm, we could call pg_get_viewdef() on dependent views and then verify that the resulting view compiles without error.=20 For what it's worth, I like this idea. I do ALTER TABLEs infrequently enough that I would prefer to spend a little extra time to make sure things are consistent. Adam Tomjack [1] $ pg_dump -U postgres -S postgres test > test.sql $ psql -U postgres -d test -c "DROP SCHEMA public CASCADE;" $ psql -U postgres -d test -c "DROP LANGUAGE plpgsql CASCADE;" $ psql -U postgres -d test -c "CREATE SCHEMA public AUTHORIZATION dbusername;" $ psql -U postgres -d test -f test.sql ... psql:test.sql:1396: ERROR: common column name "aid" appears more than once in left table psql:test.sql:1399: ERROR: relation "public.v_a_b_c" does not exist ...