Skip to content

Fix owner_rels.cid foreign key reference #926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 1, 2020

Conversation

Nemo157
Copy link
Member

@Nemo157 Nemo157 commented Aug 1, 2020

Also improves testing to catch attempts to use incorrect foreign keys.

@Nemo157
Copy link
Member Author

Nemo157 commented Aug 1, 2020

I also checked the code, everywhere uses owner_rels.cid to refer to crates, not releases.

Comment on lines +246 to +251
SELECT relname
FROM pg_class
INNER JOIN pg_namespace
ON pg_class.relnamespace = pg_namespace.oid
WHERE pg_class.relkind = 'S'
AND pg_namespace.nspname = $1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dark magics 😨

Comment on lines +375 to +376
ALTER TABLE owner_rels DROP CONSTRAINT owner_rels_cid_fkey;
ALTER TABLE owner_rels ADD FOREIGN KEY (cid) REFERENCES crates(id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if I understand this correctly:

  • The code uses cid to mean crate_id everywhere.
  • The database foreign key referenced the releases.id column, which didn't match the usage.
  • The reason we didn't catch it until now is because both are strictly increasing, and there are always more releases than crates. So the foreign constraint held even though the semantic meaning was incorrect.
  • This changes the foreign key constraint but nothing else, because all the joins are already done on owners INNER JOIN crates ON owners.cid = crates.id, which is the correct behavior.

However I don't think the last point is entirely true: When I wrote delete_crate I thought this was actually the release id. So I think that delete_crate is actually very broken right now and needs to be fixed as part of this change:

&format!("DELETE FROM {} WHERE {} IN (SELECT id FROM releases WHERE crate_id = $1 AND version = $2)", table, column),
and
"DELETE FROM {} WHERE {} IN (SELECT id FROM releases WHERE crate_id = $1)",

cc @pietroalbini: do not delete any more crates until this is fixed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that all sounds correct, I've fixed it in the latest commit. I don't see any easy way to really test the behaviour.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fortunately this part of the code is (since #917) self-correcting so the worst that can happen is that the owner is missing until the next publish. Thanks for working on this :)

@Nemo157 Nemo157 force-pushed the fix-owner-rels-refs branch from f4cb1c4 to 43940d5 Compare August 1, 2020 15:41
@@ -105,6 +104,7 @@ fn delete_crate_from_database(conn: &Connection, name: &str, crate_id: i32) -> R
&[&crate_id],
)?;
}
transaction.execute("DELETE FROM owner_rels WHERE cid = $1;", &[&crate_id])?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to say you only do this for deleting a crate, not a version, then I realized that's the right behavior and it was just buggy before 😅

@jyn514 jyn514 merged commit cab5014 into rust-lang:master Aug 1, 2020
@Nemo157 Nemo157 deleted the fix-owner-rels-refs branch January 22, 2021 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants