find_schema_problems(): report problems in a stable order

Several sections had no ORDER BY, so when one section found more than one
problem PostgreSQL could return them in any order (found by new
break-one-thing tests). Every section is now sorted. Output is otherwise
unchanged; no version bump.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
peter 2026-10-06 12:18:54 +01:00
parent 9032fd3a45
commit 738fe0fe2d

View file

@ -12,7 +12,8 @@
-- meta.find_schema_problems()
-- --------------------------------------------------------------------------
--
-- Returns one row per problem: (object, problem). Read-only.
-- Returns one row per problem: (object, problem), in a stable order
-- (section by section, each sorted). Read-only.
--
-- The expectations below mirror 00..08. When any of those files changes,
-- update this file in the same commit. The release tests (a freshly
@ -42,12 +43,14 @@ BEGIN
RETURN QUERY
SELECT 'schema ' || s, 'missing'
FROM unnest(ARRAY['meta', 'series', 'log']) AS s
WHERE NOT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = s);
WHERE NOT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = s)
ORDER BY 1;
RETURN QUERY
SELECT 'extension ' || e, 'missing'
FROM unnest(ARRAY['pg_trgm']) AS e
WHERE NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = e);
WHERE NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = e)
ORDER BY 1;
RETURN QUERY
SELECT 'sequence ' || s, 'missing'
@ -57,7 +60,8 @@ BEGIN
'log.pending_changes_id_seq',
'log.script_log_id_seq'
]) AS s
WHERE to_regclass(s) IS NULL;
WHERE to_regclass(s) IS NULL
ORDER BY 1;
-- Tables and columns ----------------------------------------------------
RETURN QUERY
@ -231,7 +235,8 @@ BEGIN
) AS c(tbl, name)
WHERE to_regclass(c.tbl) IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM pg_constraint k
WHERE k.conrelid = to_regclass(c.tbl) AND k.conname = c.name);
WHERE k.conrelid = to_regclass(c.tbl) AND k.conname = c.name)
ORDER BY 1;
RETURN QUERY
SELECT 'index ' || i.idx, 'missing'
@ -253,12 +258,14 @@ BEGIN
('log.idx_script_log_series', 'log.script_log'),
('log.idx_script_log_level', 'log.script_log')
) AS i(idx, tbl)
WHERE to_regclass(i.tbl) IS NOT NULL AND to_regclass(i.idx) IS NULL;
WHERE to_regclass(i.tbl) IS NOT NULL AND to_regclass(i.idx) IS NULL
ORDER BY 1;
RETURN QUERY
SELECT 'view ' || v, 'missing'
FROM unnest(ARRAY['log.script_log_recent']) AS v
WHERE to_regclass(v) IS NULL;
WHERE to_regclass(v) IS NULL
ORDER BY 1;
-- Functions (compared by whitespace-insensitive body fingerprint) -------
RETURN QUERY
@ -285,7 +292,8 @@ BEGIN
WHERE NOT EXISTS (SELECT 1 FROM pg_proc p
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE n.nspname || '.' || p.proname = f.name
AND md5(btrim(regexp_replace(p.prosrc, '\s+', ' ', 'g'))) = f.fingerprint);
AND md5(btrim(regexp_replace(p.prosrc, '\s+', ' ', 'g'))) = f.fingerprint)
ORDER BY 1;
-- Drop-protection event trigger -----------------------------------------
RETURN QUERY
@ -302,7 +310,8 @@ BEGIN
(CASE WHEN t.evtfoid::regproc::text <> 'meta.prevent_direct_drop'
THEN 'calls ' || t.evtfoid::regproc::text || ', expected meta.prevent_direct_drop' END)
) AS x(p)
WHERE t.evtname = 'prevent_series_drops' AND p IS NOT NULL;
WHERE t.evtname = 'prevent_series_drops' AND p IS NOT NULL
ORDER BY 2;
-- Reference data and version row ----------------------------------------
RETURN QUERY
@ -321,7 +330,8 @@ BEGIN
) AS e(tbl, expected)
WHERE to_regclass(e.tbl) IS NOT NULL
) AS r
WHERE r.actual < r.expected;
WHERE r.actual < r.expected
ORDER BY 1;
-- Series schema registry ------------------------------------------------
-- Only REGISTERED schemas are examined; user schemas are never looked at.