-- Migration p2-003: Schemaobjekte der Anwendungsrolle uebereignen -- -- psql "$ADMIN_DATABASE_URL" -v ON_ERROR_STOP=1 -f migrations/p2-003-eigentuemer.sql -- -- Die Datenbank wurzelwerk gehoert der Rolle wurzelwerk, ihre Tabellen aber -- postgres: schema.sql wurde beim Ingest-Deploy als Superuser eingespielt. -- Folge ist, dass die Anwendungsrolle an ihrem eigenen Schema nichts aendern -- darf - jedes `alter table` scheitert mit "must be owner of table". -- -- Die uebrigen Dienste auf derselben Instanz halten es anders herum: gitea -- und hedgedoc besitzen ihre Tabellen vollstaendig. Diese Migration stellt -- denselben Zustand her. Der Radius bleibt auf die Datenbank wurzelwerk -- beschraenkt; an gitea und hedgedoc wird nicht geruehrt. -- -- Danach laufen Migrationen ohne Superuser, also ueber DATABASE_URL statt -- ueber den Socket im Container. Ausnahme bleibt `create extension` in -- p2-002, sofern die Erweiterung nicht als trusted gefuehrt wird. -- -- Diese Migration ist die einzige, die zwingend als Superuser laeuft - sie -- verschenkt Rechte, die sie selbst nicht mehr braeuchte. begin; do $$ declare ziel constant name := 'wurzelwerk'; o record; n integer := 0; begin if not exists (select 1 from pg_roles where rolname = ziel) then raise exception 'Rolle % existiert nicht', ziel; end if; -- Tabellen, Sichten und freistehende Sequenzen. -- -- Ausgenommen sind zwei Gruppen. Erstens Objekte einer Erweiterung -- (pg_trgm, vector): die gehoeren dem Superuser und werden mit der -- Erweiterung verwaltet, nicht von Hand. Zweitens Sequenzen, die an -- einer Spalte haengen - alles aus bigserial. Die folgen dem Eigentuemer -- ihrer Tabelle von selbst und lassen sich nicht einzeln uebereignen -- ("is linked to table"). Deshalb erst die Tabellen, dann der Rest. for o in select c.oid::regclass::text as name, case c.relkind when 'S' then 'sequence' when 'v' then 'view' when 'm' then 'materialized view' else 'table' end as art from pg_class c join pg_namespace n on n.oid = c.relnamespace where n.nspname = 'public' and c.relkind in ('r', 'p', 'S', 'v', 'm') and pg_get_userbyid(c.relowner) <> ziel and not exists (select 1 from pg_depend d where d.classid = 'pg_class'::regclass and d.objid = c.oid and d.deptype = 'e') and not exists (select 1 from pg_depend d where d.classid = 'pg_class'::regclass and d.objid = c.oid and d.deptype = 'a' and d.refclassid = 'pg_class'::regclass) order by case c.relkind when 'r' then 0 when 'p' then 0 when 'v' then 1 when 'm' then 1 else 2 end loop execute format('alter %s %s owner to %I', o.art, o.name, ziel); n := n + 1; end loop; -- Funktionen ebenso. Ohne sie duerfte die Rolle ihre eigenen Helfer -- spaeter nicht mehr ersetzen. for o in select p.oid::regprocedure::text as name from pg_proc p join pg_namespace n on n.oid = p.pronamespace where n.nspname = 'public' and pg_get_userbyid(p.proowner) <> ziel and not exists (select 1 from pg_depend d where d.classid = 'pg_proc'::regclass and d.objid = p.oid and d.deptype = 'e') loop execute format('alter function %s owner to %I', o.name, ziel); n := n + 1; end loop; raise notice 'uebereignet: % Objekte an %', n, ziel; end $$; -- Neue Objekte gehoeren ohnehin dem, der sie anlegt; das Recht dazu im -- Schema public ist seit PostgreSQL 15 nicht mehr selbstverstaendlich. grant create, usage on schema public to wurzelwerk; insert into schema_migrationen (name) values ('p2-003-eigentuemer') on conflict (name) do nothing; commit;