I think all the hard work can be done with a couple of database queries. The attached file is a reimplementation.
This certainly runs without errors on Postgres. From reading the docs, I believe MySQL will undersand the two queries, but I have not had time to test yet. I see no reason why other databases should not cope with this SQL.
I think it is doing the right thing, but it would definitely be good if people could code review this.
It runs 10 or 100 times faster than the old code on some of our big metacourses. Manually assigning or unassigning a role in a child course went from 25 seconds to 1.5 on one of our courses. (For OU people, that was courseid 1111 on learnacct.)