The problematic underlying query that postgres was running as part of the alter statement was this:
SELECT
fk."a",
fk."b",
fk."c"
FROM ONLY "public"."b" fk
JOIN ONLY "public"."a" pk
ON ( pk."a" OPERATOR(pg_catalog.=) fk."a"
AND pk."b" OPERATOR(pg_catalog.=) fk."b"
AND pk."c" OPERATOR(pg_catalog.=) fk."c")
WHERE pk."a" IS NULL
AND (fk."a" IS NOT NULL
AND fk."b" IS NOT NULL
AND fk."b" IS NOT NULL);
So I changed the names, but it apparently was important that the name of column "b" in both tables was actually "rowid". After speaking with my DBA for a while, we just guessed that maybe rowid was a reserved word in postgres or at least the bug was related to that. Turns out it was; I renamed the column in both tables to "row_id" and the problem was resolved. Doesn't work:
SELECT
fk."templateid",
fk."rowid",
fk."colid"
FROM ONLY "public"."b" fk
JOIN ONLY "public"."a" pk
ON ( pk."templateid" OPERATOR(pg_catalog.=) fk."templateid"
AND pk."rowid" OPERATOR(pg_catalog.=) fk."rowid"
AND pk."colid" OPERATOR(pg_catalog.=) fk."colid")
WHERE pk."templateid" IS NULL
AND (fk."templateid" IS NOT NULL
AND fk."rowid" IS NOT NULL
AND fk."colid" IS NOT NULL);
Works :
SELECT
fk."templateid",
fk."row_id",
fk."col_id"
FROM ONLY "public"."b" fk
JOIN ONLY "public"."a" pk
ON ( pk."templateid" OPERATOR(pg_catalog.=) fk."templateid"
AND pk."row_id" OPERATOR(pg_catalog.=) fk."row_id"
AND pk."col_id" OPERATOR(pg_catalog.=) fk."col_id")
WHERE pk."templateid" IS NULL
AND (fk."templateid" IS NOT NULL
AND fk."row_id" IS NOT NULL
AND fk."col_id" IS NOT NULL);
(I just changed colid for naming consistency, it was not contributing to the problem)