mirror of https://github.com/postgres/postgres
It's essential that initdb.c's setup_depend() scan each system catalog that could contain objects that need to have "p" (pin) entries in pg_depend or pg_shdepend. Forgetting to add that, either when a catalog is first invented or when it first acquires DATA() entries, is an obvious bug hazard. We can detect such omissions at reasonable cost by probing every OID-containing system catalog to see whether the lowest-numbered OID in it is pinned. If so, the catalog must have been properly accounted for in setup_depend(). If the lowest OID is above FirstNormalObjectId then the catalog must have been empty at the end of initdb, so it doesn't matter. There are a small number of catalogs whose first entry is made later in initdb than setup_depend(), resulting in nonempty expected output of the test, but these can be manually inspected to see that they are OK. Any future mistake of this ilk will manifest as a new entry in the test's output. Since pg_conversion is already in the test's output, add it to the set of catalogs scanned by setup_depend(). That has no effect today (hence, no catversion bump here) but it will protect us if we ever do add pin-worthy conversions. This test is very much like the catalog sanity checks embodied in opr_sanity.sql and type_sanity.sql, but testing pg_depend doesn't seem to fit naturally into either of those scripts' charters. Hence, invent a new test script misc_sanity.sql, which can be a home for this as well as tests on any other catalogs we might want in future. Discussion: https://postgr.es/m/8068.1498155068@sss.pgh.pa.uspull/23/head
parent
da2322883b
commit
8be8510cf8
@ -0,0 +1,78 @@ |
||||
-- |
||||
-- MISC_SANITY |
||||
-- Sanity checks for common errors in making system tables that don't fit |
||||
-- comfortably into either opr_sanity or type_sanity. |
||||
-- |
||||
-- Every test failure in this file should be closely inspected. |
||||
-- The description of the failing test should be read carefully before |
||||
-- adjusting the expected output. In most cases, the queries should |
||||
-- not find *any* matching entries. |
||||
-- |
||||
-- NB: run this test early, because some later tests create bogus entries. |
||||
-- **************** pg_depend **************** |
||||
-- Look for illegal values in pg_depend fields. |
||||
-- classid/objid can be zero, but only in 'p' entries |
||||
SELECT * |
||||
FROM pg_depend as d1 |
||||
WHERE refclassid = 0 OR refobjid = 0 OR |
||||
deptype NOT IN ('a', 'e', 'i', 'n', 'p') OR |
||||
(deptype != 'p' AND (classid = 0 OR objid = 0)) OR |
||||
(deptype = 'p' AND (classid != 0 OR objid != 0 OR objsubid != 0)); |
||||
classid | objid | objsubid | refclassid | refobjid | refobjsubid | deptype |
||||
---------+-------+----------+------------+----------+-------------+--------- |
||||
(0 rows) |
||||
|
||||
-- **************** pg_shdepend **************** |
||||
-- Look for illegal values in pg_shdepend fields. |
||||
-- classid/objid can be zero, but only in 'p' entries |
||||
SELECT * |
||||
FROM pg_shdepend as d1 |
||||
WHERE refclassid = 0 OR refobjid = 0 OR |
||||
deptype NOT IN ('a', 'o', 'p', 'r') OR |
||||
(deptype != 'p' AND (dbid = 0 OR classid = 0 OR objid = 0)) OR |
||||
(deptype = 'p' AND (dbid != 0 OR classid != 0 OR objid != 0 OR objsubid != 0)); |
||||
dbid | classid | objid | objsubid | refclassid | refobjid | deptype |
||||
------+---------+-------+----------+------------+----------+--------- |
||||
(0 rows) |
||||
|
||||
-- Check each OID-containing system catalog to see if its lowest-numbered OID |
||||
-- is pinned. If not, and if that OID was generated during initdb, then |
||||
-- perhaps initdb forgot to scan that catalog for pinnable entries. |
||||
-- Generally, it's okay for a catalog to be listed in the output of this |
||||
-- test if that catalog is scanned by initdb.c's setup_depend() function; |
||||
-- whatever OID the test is complaining about must have been added later |
||||
-- in initdb, where it intentionally isn't pinned. Legitimate exceptions |
||||
-- to that rule are listed in the comments in setup_depend(). |
||||
do $$ |
||||
declare relnm text; |
||||
reloid oid; |
||||
shared bool; |
||||
lowoid oid; |
||||
pinned bool; |
||||
begin |
||||
for relnm, reloid, shared in |
||||
select relname, oid, relisshared from pg_class |
||||
where relhasoids and oid < 16384 order by 1 |
||||
loop |
||||
execute 'select min(oid) from ' || relnm into lowoid; |
||||
continue when lowoid is null or lowoid >= 16384; |
||||
if shared then |
||||
pinned := exists(select 1 from pg_shdepend |
||||
where refclassid = reloid and refobjid = lowoid |
||||
and deptype = 'p'); |
||||
else |
||||
pinned := exists(select 1 from pg_depend |
||||
where refclassid = reloid and refobjid = lowoid |
||||
and deptype = 'p'); |
||||
end if; |
||||
if not pinned then |
||||
raise notice '% contains unpinned initdb-created object(s)', relnm; |
||||
end if; |
||||
end loop; |
||||
end$$; |
||||
NOTICE: pg_constraint contains unpinned initdb-created object(s) |
||||
NOTICE: pg_conversion contains unpinned initdb-created object(s) |
||||
NOTICE: pg_database contains unpinned initdb-created object(s) |
||||
NOTICE: pg_extension contains unpinned initdb-created object(s) |
||||
NOTICE: pg_rewrite contains unpinned initdb-created object(s) |
||||
NOTICE: pg_tablespace contains unpinned initdb-created object(s) |
||||
@ -0,0 +1,74 @@ |
||||
-- |
||||
-- MISC_SANITY |
||||
-- Sanity checks for common errors in making system tables that don't fit |
||||
-- comfortably into either opr_sanity or type_sanity. |
||||
-- |
||||
-- Every test failure in this file should be closely inspected. |
||||
-- The description of the failing test should be read carefully before |
||||
-- adjusting the expected output. In most cases, the queries should |
||||
-- not find *any* matching entries. |
||||
-- |
||||
-- NB: run this test early, because some later tests create bogus entries. |
||||
|
||||
|
||||
-- **************** pg_depend **************** |
||||
|
||||
-- Look for illegal values in pg_depend fields. |
||||
-- classid/objid can be zero, but only in 'p' entries |
||||
|
||||
SELECT * |
||||
FROM pg_depend as d1 |
||||
WHERE refclassid = 0 OR refobjid = 0 OR |
||||
deptype NOT IN ('a', 'e', 'i', 'n', 'p') OR |
||||
(deptype != 'p' AND (classid = 0 OR objid = 0)) OR |
||||
(deptype = 'p' AND (classid != 0 OR objid != 0 OR objsubid != 0)); |
||||
|
||||
-- **************** pg_shdepend **************** |
||||
|
||||
-- Look for illegal values in pg_shdepend fields. |
||||
-- classid/objid can be zero, but only in 'p' entries |
||||
|
||||
SELECT * |
||||
FROM pg_shdepend as d1 |
||||
WHERE refclassid = 0 OR refobjid = 0 OR |
||||
deptype NOT IN ('a', 'o', 'p', 'r') OR |
||||
(deptype != 'p' AND (dbid = 0 OR classid = 0 OR objid = 0)) OR |
||||
(deptype = 'p' AND (dbid != 0 OR classid != 0 OR objid != 0 OR objsubid != 0)); |
||||
|
||||
|
||||
-- Check each OID-containing system catalog to see if its lowest-numbered OID |
||||
-- is pinned. If not, and if that OID was generated during initdb, then |
||||
-- perhaps initdb forgot to scan that catalog for pinnable entries. |
||||
-- Generally, it's okay for a catalog to be listed in the output of this |
||||
-- test if that catalog is scanned by initdb.c's setup_depend() function; |
||||
-- whatever OID the test is complaining about must have been added later |
||||
-- in initdb, where it intentionally isn't pinned. Legitimate exceptions |
||||
-- to that rule are listed in the comments in setup_depend(). |
||||
|
||||
do $$ |
||||
declare relnm text; |
||||
reloid oid; |
||||
shared bool; |
||||
lowoid oid; |
||||
pinned bool; |
||||
begin |
||||
for relnm, reloid, shared in |
||||
select relname, oid, relisshared from pg_class |
||||
where relhasoids and oid < 16384 order by 1 |
||||
loop |
||||
execute 'select min(oid) from ' || relnm into lowoid; |
||||
continue when lowoid is null or lowoid >= 16384; |
||||
if shared then |
||||
pinned := exists(select 1 from pg_shdepend |
||||
where refclassid = reloid and refobjid = lowoid |
||||
and deptype = 'p'); |
||||
else |
||||
pinned := exists(select 1 from pg_depend |
||||
where refclassid = reloid and refobjid = lowoid |
||||
and deptype = 'p'); |
||||
end if; |
||||
if not pinned then |
||||
raise notice '% contains unpinned initdb-created object(s)', relnm; |
||||
end if; |
||||
end loop; |
||||
end$$; |
||||
Loading…
Reference in new issue