Repository navigation
Dropped owner roles: reassign_owned, drop_owned, orphans, on_drop_owned (M10 step 6) - #57
Merged
Merged
Conversation
…e sweep
DESIGN.md §5.7, §14 items 44 (a, refuse) and 45 (b), work breakdown step 6.
- warren.reassign_owned(old, new) and warren.drop_owned(role): SQL
counterparts of REASSIGN OWNED and DROP OWNED for graphs, their vectors
and reader entries, needing the privileges of the role
(has_privs_of_role) as the commands do.
- warren.on_drop_owned(): an event-trigger function over the raw fcinfo,
for a superuser's CREATE EVENT TRIGGER ... WHEN TAG IN ('DROP OWNED');
the extension never creates the trigger. It refuses a direct call
(39P03), reads the roles from the DropOwnedStmt (get_rolespec_oid),
skips those that do not exist or whose privileges the caller lacks, and
refuses with 2BP01 while one owns graphs, naming them and both
functions; otherwise it removes the roles' reader entries and vectors as
the catalog owner.
- warren.orphans() and warren.drop_orphans(): the sweep after a bare
DROP ROLE.
- Item 45b: members of the extension's owner may drop orphaned graphs
(drop_graph, drop_orphans); only a superuser may adopt one with
set_owner, which refused it before.
- Quota rows (step 7) get a marked seam where they will be deleted.
Every new function is in parallel_labels and the guard's CALLS, and in
sql/pg_warren--0.6.0.sql and the 0.5.0 -> 0.6.0 upgrade script.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Rxfe2L3iVjSwSBPdUu1Ke
- test/sql/drop_owned.sql: the standard procedure without the trigger orphans graphs, which orphans() and drop_orphans() sweep; with it, DROP OWNED is refused while the role owns graphs, and cleans up after reassign_owned or for a role that owns none; DROP EXTENSION needs CASCADE. - trusted_install.sql: non-superusers reassign and drop a leaving role's graphs; the installer drops an orphan but may not adopt one, and cannot create the trigger, whose presence makes its DROP EXTENSION need CASCADE. - test/dump.py: both dumps carry the trigger; the superuser's restore recreates it, and the installer's restore fails at its two statements and nowhere else. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Rxfe2L3iVjSwSBPdUu1Ke
docs/semantics.md gains "Dropping a role": the procedure in each database before DROP ROLE, the opt-in event trigger, the sweep and who may act on an orphan. DESIGN.md §5.7 records step 6 as done with an Implemented note (including the 39P03 for a direct call, where the text said 39P01, and the trigger leaving roles the caller lacks the privileges of to DROP OWNED); §7 and the API listing follow. CHANGELOG 0.6.0, README and docs/limits.md too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Rxfe2L3iVjSwSBPdUu1Ke
# Conflicts: # DESIGN.md
- drop_orphans locks each pass's candidate rows FOR UPDATE, then deletes or updates them by key in a statement of its own: EvalPlanQual re-checked "no such role" under the first snapshot, so a graph adopted for, or a reader granted to, a role created by the transaction it waited for was dropped or pruned. - The deletes that follow a creator check (drop_vector, replacement, compact's move) delete by id and the checked creator (vector::Checked), so one queued behind a reassign_owned fails with 40001 instead of deleting the new creator's vector. - Dropping orphans needs what DROP EXTENSION needs of the extension's owner: on PG 16+ its privileges or SET ROLE to it, not a bare membership (WITH INHERIT FALSE, SET FALSE); membership on PG 15. - drop_owned and reassign_owned refuse the bootstrap superuser (2BP01), as the commands do; the trigger takes each named role once; the get_rolespec_oid SAFETY comment says PUBLIC would raise. - test/sql/dropped_roles_race.sql queues reassign_owned, drop_owned, drop_orphans and drop_vector behind uncommitted set_owner, refresh, grant and reassign_owned; its adoption, reader and drop_vector cases failed before the fixes, as did the new pg_tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Rxfe2L3iVjSwSBPdUu1Ke
DESIGN.md §5.7's Implemented note records the locking sweep, the creator-checked vector deletes, the PG 16+ rule for the extension's owner, the bootstrap refusal, and that the trigger's refusal reads without a lock (an uncommitted transfer to the role is missed and left to the sweep); docs/semantics.md and the CHANGELOG follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Rxfe2L3iVjSwSBPdUu1Ke
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is M10 step 6 (DESIGN.md §5.7, "Dropped owner roles"). It implements §14 items 44a and 45b, as the owner decided them.
New functions
warren.reassign_owned(old, new)givesold's graphs tonewand makesnewthe creator ofold's vectors. It returns the number of graphs moved.set_owner's rules, but opens no source queries, asREASSIGN OWNEDchecks none.oldand must be able to becomenew.warren.drop_owned(role)drops the role's graphs, deletes the vectors it wrote on other graphs, and removes it from every readers list.warren.on_drop_owned()is the function for an optionalddl_command_startevent trigger, which a superuser creates. The extension script never creates the trigger;docs/semantics.mddocuments how to opt in.warren.orphans()lists graphs, reader entries and vectors whose role was dropped.warren.drop_orphans()removes them.set_owner.Deviations from §5.7 (both recorded in DESIGN.md)
on_drop_ownedgets 39P03 (event_trigger_protocol_violated), which is what Postgres's own event-trigger functions raise, not 39P01.DROP OWNED's privileges only afterddl_command_start, so without this an unprivilegedDROP OWNED BY victimwould get a 2BP01 listing the victim's graph names. With it,DROP OWNEDraises its own 42501.Tests
test/run.py:drop_owned,trusted_install,set_owner_race,search_path_noticeandlock_reread_race, in normal and--trustedmodes.test/dump.pywith the trigger present: a superuser's restore recreates it; the installer's restore fails only at the trigger's statements.test/upgrade.pypasses,schema-drift.shreports no drift, and acargo checkon PG 15 is clean.The quota rows are step 7: each cleanup has a comment marking where they go.
Generated by Claude Code