]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/1405.schema.add_cancel_info_to_hold_requests.sql
Stamping upgrade scripts and refifying baseline schema
[working/Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / 1405.schema.add_cancel_info_to_hold_requests.sql
1 BEGIN;
2
3 SELECT evergreen.upgrade_deps_block_check('1405', :eg_version);
4
5 ALTER TABLE action.hold_request 
6 ADD COLUMN canceled_by INT REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
7 ADD COLUMN canceling_ws INT REFERENCES actor.workstation (id) DEFERRABLE INITIALLY DEFERRED;
8
9 CREATE INDEX hold_request_canceled_by_idx ON action.hold_request (canceled_by);
10 CREATE INDEX hold_request_canceling_ws_idx ON action.hold_request (canceling_ws);
11
12 CREATE OR REPLACE FUNCTION actor.usr_merge( src_usr INT, dest_usr INT, del_addrs BOOLEAN, del_cards BOOLEAN, deactivate_cards BOOLEAN ) RETURNS VOID AS $$
13 DECLARE
14         suffix TEXT;
15         bucket_row RECORD;
16         picklist_row RECORD;
17         queue_row RECORD;
18         folder_row RECORD;
19 BEGIN
20
21     -- Bail if src_usr equals dest_usr because the result of merging a
22     -- user with itself is not what you want.
23     IF src_usr = dest_usr THEN
24         RETURN;
25     END IF;
26
27     -- do some initial cleanup 
28     UPDATE actor.usr SET card = NULL WHERE id = src_usr;
29     UPDATE actor.usr SET mailing_address = NULL WHERE id = src_usr;
30     UPDATE actor.usr SET billing_address = NULL WHERE id = src_usr;
31
32     -- actor.*
33     IF del_cards THEN
34         DELETE FROM actor.card where usr = src_usr;
35     ELSE
36         IF deactivate_cards THEN
37             UPDATE actor.card SET active = 'f' WHERE usr = src_usr;
38         END IF;
39         UPDATE actor.card SET usr = dest_usr WHERE usr = src_usr;
40     END IF;
41
42
43     IF del_addrs THEN
44         DELETE FROM actor.usr_address WHERE usr = src_usr;
45     ELSE
46         UPDATE actor.usr_address SET usr = dest_usr WHERE usr = src_usr;
47     END IF;
48
49     UPDATE actor.usr_message SET usr = dest_usr WHERE usr = src_usr;
50     -- dupes are technically OK in actor.usr_standing_penalty, should manually delete them...
51     UPDATE actor.usr_standing_penalty SET usr = dest_usr WHERE usr = src_usr;
52     PERFORM actor.usr_merge_rows('actor.usr_org_unit_opt_in', 'usr', src_usr, dest_usr);
53     PERFORM actor.usr_merge_rows('actor.usr_setting', 'usr', src_usr, dest_usr);
54
55     -- permission.*
56     PERFORM actor.usr_merge_rows('permission.usr_perm_map', 'usr', src_usr, dest_usr);
57     PERFORM actor.usr_merge_rows('permission.usr_object_perm_map', 'usr', src_usr, dest_usr);
58     PERFORM actor.usr_merge_rows('permission.usr_grp_map', 'usr', src_usr, dest_usr);
59     PERFORM actor.usr_merge_rows('permission.usr_work_ou_map', 'usr', src_usr, dest_usr);
60
61
62     -- container.*
63         
64         -- For each *_bucket table: transfer every bucket belonging to src_usr
65         -- into the custody of dest_usr.
66         --
67         -- In order to avoid colliding with an existing bucket owned by
68         -- the destination user, append the source user's id (in parenthesese)
69         -- to the name.  If you still get a collision, add successive
70         -- spaces to the name and keep trying until you succeed.
71         --
72         FOR bucket_row in
73                 SELECT id, name
74                 FROM   container.biblio_record_entry_bucket
75                 WHERE  owner = src_usr
76         LOOP
77                 suffix := ' (' || src_usr || ')';
78                 LOOP
79                         BEGIN
80                                 UPDATE  container.biblio_record_entry_bucket
81                                 SET     owner = dest_usr, name = name || suffix
82                                 WHERE   id = bucket_row.id;
83                         EXCEPTION WHEN unique_violation THEN
84                                 suffix := suffix || ' ';
85                                 CONTINUE;
86                         END;
87                         EXIT;
88                 END LOOP;
89         END LOOP;
90
91         FOR bucket_row in
92                 SELECT id, name
93                 FROM   container.call_number_bucket
94                 WHERE  owner = src_usr
95         LOOP
96                 suffix := ' (' || src_usr || ')';
97                 LOOP
98                         BEGIN
99                                 UPDATE  container.call_number_bucket
100                                 SET     owner = dest_usr, name = name || suffix
101                                 WHERE   id = bucket_row.id;
102                         EXCEPTION WHEN unique_violation THEN
103                                 suffix := suffix || ' ';
104                                 CONTINUE;
105                         END;
106                         EXIT;
107                 END LOOP;
108         END LOOP;
109
110         FOR bucket_row in
111                 SELECT id, name
112                 FROM   container.copy_bucket
113                 WHERE  owner = src_usr
114         LOOP
115                 suffix := ' (' || src_usr || ')';
116                 LOOP
117                         BEGIN
118                                 UPDATE  container.copy_bucket
119                                 SET     owner = dest_usr, name = name || suffix
120                                 WHERE   id = bucket_row.id;
121                         EXCEPTION WHEN unique_violation THEN
122                                 suffix := suffix || ' ';
123                                 CONTINUE;
124                         END;
125                         EXIT;
126                 END LOOP;
127         END LOOP;
128
129         FOR bucket_row in
130                 SELECT id, name
131                 FROM   container.user_bucket
132                 WHERE  owner = src_usr
133         LOOP
134                 suffix := ' (' || src_usr || ')';
135                 LOOP
136                         BEGIN
137                                 UPDATE  container.user_bucket
138                                 SET     owner = dest_usr, name = name || suffix
139                                 WHERE   id = bucket_row.id;
140                         EXCEPTION WHEN unique_violation THEN
141                                 suffix := suffix || ' ';
142                                 CONTINUE;
143                         END;
144                         EXIT;
145                 END LOOP;
146         END LOOP;
147
148         UPDATE container.user_bucket_item SET target_user = dest_usr WHERE target_user = src_usr;
149
150     -- vandelay.*
151         -- transfer queues the same way we transfer buckets (see above)
152         FOR queue_row in
153                 SELECT id, name
154                 FROM   vandelay.queue
155                 WHERE  owner = src_usr
156         LOOP
157                 suffix := ' (' || src_usr || ')';
158                 LOOP
159                         BEGIN
160                                 UPDATE  vandelay.queue
161                                 SET     owner = dest_usr, name = name || suffix
162                                 WHERE   id = queue_row.id;
163                         EXCEPTION WHEN unique_violation THEN
164                                 suffix := suffix || ' ';
165                                 CONTINUE;
166                         END;
167                         EXIT;
168                 END LOOP;
169         END LOOP;
170
171     UPDATE vandelay.session_tracker SET usr = dest_usr WHERE usr = src_usr;
172
173     -- money.*
174     PERFORM actor.usr_merge_rows('money.collections_tracker', 'usr', src_usr, dest_usr);
175     PERFORM actor.usr_merge_rows('money.collections_tracker', 'collector', src_usr, dest_usr);
176     UPDATE money.billable_xact SET usr = dest_usr WHERE usr = src_usr;
177     UPDATE money.billing SET voider = dest_usr WHERE voider = src_usr;
178     UPDATE money.bnm_payment SET accepting_usr = dest_usr WHERE accepting_usr = src_usr;
179
180     -- action.*
181     UPDATE action.circulation SET usr = dest_usr WHERE usr = src_usr;
182     UPDATE action.circulation SET circ_staff = dest_usr WHERE circ_staff = src_usr;
183     UPDATE action.circulation SET checkin_staff = dest_usr WHERE checkin_staff = src_usr;
184     UPDATE action.usr_circ_history SET usr = dest_usr WHERE usr = src_usr;
185
186     UPDATE action.hold_request SET usr = dest_usr WHERE usr = src_usr;
187     UPDATE action.hold_request SET fulfillment_staff = dest_usr WHERE fulfillment_staff = src_usr;
188     UPDATE action.hold_request SET requestor = dest_usr WHERE requestor = src_usr;
189     UPDATE action.hold_request SET canceled_by = dest_usr WHERE canceled_by = src_usr;
190     UPDATE action.hold_notification SET notify_staff = dest_usr WHERE notify_staff = src_usr;
191
192     UPDATE action.in_house_use SET staff = dest_usr WHERE staff = src_usr;
193     UPDATE action.non_cataloged_circulation SET staff = dest_usr WHERE staff = src_usr;
194     UPDATE action.non_cataloged_circulation SET patron = dest_usr WHERE patron = src_usr;
195     UPDATE action.non_cat_in_house_use SET staff = dest_usr WHERE staff = src_usr;
196     UPDATE action.survey_response SET usr = dest_usr WHERE usr = src_usr;
197
198     -- acq.*
199     UPDATE acq.fund_allocation SET allocator = dest_usr WHERE allocator = src_usr;
200         UPDATE acq.fund_transfer SET transfer_user = dest_usr WHERE transfer_user = src_usr;
201     UPDATE acq.invoice SET closed_by = dest_usr WHERE closed_by = src_usr;
202
203         -- transfer picklists the same way we transfer buckets (see above)
204         FOR picklist_row in
205                 SELECT id, name
206                 FROM   acq.picklist
207                 WHERE  owner = src_usr
208         LOOP
209                 suffix := ' (' || src_usr || ')';
210                 LOOP
211                         BEGIN
212                                 UPDATE  acq.picklist
213                                 SET     owner = dest_usr, name = name || suffix
214                                 WHERE   id = picklist_row.id;
215                         EXCEPTION WHEN unique_violation THEN
216                                 suffix := suffix || ' ';
217                                 CONTINUE;
218                         END;
219                         EXIT;
220                 END LOOP;
221         END LOOP;
222
223     UPDATE acq.purchase_order SET owner = dest_usr WHERE owner = src_usr;
224     UPDATE acq.po_note SET creator = dest_usr WHERE creator = src_usr;
225     UPDATE acq.po_note SET editor = dest_usr WHERE editor = src_usr;
226     UPDATE acq.provider_note SET creator = dest_usr WHERE creator = src_usr;
227     UPDATE acq.provider_note SET editor = dest_usr WHERE editor = src_usr;
228     UPDATE acq.lineitem_note SET creator = dest_usr WHERE creator = src_usr;
229     UPDATE acq.lineitem_note SET editor = dest_usr WHERE editor = src_usr;
230     UPDATE acq.lineitem_usr_attr_definition SET usr = dest_usr WHERE usr = src_usr;
231
232     -- asset.*
233     UPDATE asset.copy SET creator = dest_usr WHERE creator = src_usr;
234     UPDATE asset.copy SET editor = dest_usr WHERE editor = src_usr;
235     UPDATE asset.copy_note SET creator = dest_usr WHERE creator = src_usr;
236     UPDATE asset.call_number SET creator = dest_usr WHERE creator = src_usr;
237     UPDATE asset.call_number SET editor = dest_usr WHERE editor = src_usr;
238     UPDATE asset.call_number_note SET creator = dest_usr WHERE creator = src_usr;
239
240     -- serial.*
241     UPDATE serial.record_entry SET creator = dest_usr WHERE creator = src_usr;
242     UPDATE serial.record_entry SET editor = dest_usr WHERE editor = src_usr;
243
244     -- reporter.*
245     -- It's not uncommon to define the reporter schema in a replica 
246     -- DB only, so don't assume these tables exist in the write DB.
247     BEGIN
248         UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr;
249     EXCEPTION WHEN undefined_table THEN
250         -- do nothing
251     END;
252     BEGIN
253         UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr;
254     EXCEPTION WHEN undefined_table THEN
255         -- do nothing
256     END;
257     BEGIN
258         UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr;
259     EXCEPTION WHEN undefined_table THEN
260         -- do nothing
261     END;
262     BEGIN
263                 -- transfer folders the same way we transfer buckets (see above)
264                 FOR folder_row in
265                         SELECT id, name
266                         FROM   reporter.template_folder
267                         WHERE  owner = src_usr
268                 LOOP
269                         suffix := ' (' || src_usr || ')';
270                         LOOP
271                                 BEGIN
272                                         UPDATE  reporter.template_folder
273                                         SET     owner = dest_usr, name = name || suffix
274                                         WHERE   id = folder_row.id;
275                                 EXCEPTION WHEN unique_violation THEN
276                                         suffix := suffix || ' ';
277                                         CONTINUE;
278                                 END;
279                                 EXIT;
280                         END LOOP;
281                 END LOOP;
282     EXCEPTION WHEN undefined_table THEN
283         -- do nothing
284     END;
285     BEGIN
286                 -- transfer folders the same way we transfer buckets (see above)
287                 FOR folder_row in
288                         SELECT id, name
289                         FROM   reporter.report_folder
290                         WHERE  owner = src_usr
291                 LOOP
292                         suffix := ' (' || src_usr || ')';
293                         LOOP
294                                 BEGIN
295                                         UPDATE  reporter.report_folder
296                                         SET     owner = dest_usr, name = name || suffix
297                                         WHERE   id = folder_row.id;
298                                 EXCEPTION WHEN unique_violation THEN
299                                         suffix := suffix || ' ';
300                                         CONTINUE;
301                                 END;
302                                 EXIT;
303                         END LOOP;
304                 END LOOP;
305     EXCEPTION WHEN undefined_table THEN
306         -- do nothing
307     END;
308     BEGIN
309                 -- transfer folders the same way we transfer buckets (see above)
310                 FOR folder_row in
311                         SELECT id, name
312                         FROM   reporter.output_folder
313                         WHERE  owner = src_usr
314                 LOOP
315                         suffix := ' (' || src_usr || ')';
316                         LOOP
317                                 BEGIN
318                                         UPDATE  reporter.output_folder
319                                         SET     owner = dest_usr, name = name || suffix
320                                         WHERE   id = folder_row.id;
321                                 EXCEPTION WHEN unique_violation THEN
322                                         suffix := suffix || ' ';
323                                         CONTINUE;
324                                 END;
325                                 EXIT;
326                         END LOOP;
327                 END LOOP;
328     EXCEPTION WHEN undefined_table THEN
329         -- do nothing
330     END;
331
332     -- propagate preferred name values from the source user to the
333     -- destination user, but only when values are not being replaced.
334     WITH susr AS (SELECT * FROM actor.usr WHERE id = src_usr)
335     UPDATE actor.usr SET 
336         pref_prefix = 
337             COALESCE(pref_prefix, (SELECT pref_prefix FROM susr)),
338         pref_first_given_name = 
339             COALESCE(pref_first_given_name, (SELECT pref_first_given_name FROM susr)),
340         pref_second_given_name = 
341             COALESCE(pref_second_given_name, (SELECT pref_second_given_name FROM susr)),
342         pref_family_name = 
343             COALESCE(pref_family_name, (SELECT pref_family_name FROM susr)),
344         pref_suffix = 
345             COALESCE(pref_suffix, (SELECT pref_suffix FROM susr))
346     WHERE id = dest_usr;
347
348     -- Copy and deduplicate name keywords
349     -- String -> array -> rows -> DISTINCT -> array -> string
350     WITH susr AS (SELECT * FROM actor.usr WHERE id = src_usr),
351          dusr AS (SELECT * FROM actor.usr WHERE id = dest_usr)
352     UPDATE actor.usr SET name_keywords = (
353         WITH keywords AS (
354             SELECT DISTINCT UNNEST(
355                 REGEXP_SPLIT_TO_ARRAY(
356                     COALESCE((SELECT name_keywords FROM susr), '') || ' ' ||
357                     COALESCE((SELECT name_keywords FROM dusr), ''),  E'\\s+'
358                 )
359             ) AS parts
360         ) SELECT STRING_AGG(kw.parts, ' ') FROM keywords kw
361     ) WHERE id = dest_usr;
362
363     -- Finally, delete the source user
364     PERFORM actor.usr_delete(src_usr,dest_usr);
365
366 END;
367 $$ LANGUAGE plpgsql;
368
369 CREATE OR REPLACE FUNCTION actor.usr_purge_data(
370         src_usr  IN INTEGER,
371         specified_dest_usr IN INTEGER
372 ) RETURNS VOID AS $$
373 DECLARE
374         suffix TEXT;
375         renamable_row RECORD;
376         dest_usr INTEGER;
377 BEGIN
378
379         IF specified_dest_usr IS NULL THEN
380                 dest_usr := 1; -- Admin user on stock installs
381         ELSE
382                 dest_usr := specified_dest_usr;
383         END IF;
384
385     -- action_trigger.event (even doing this, event_output may--and probably does--contain PII and should have a retention/removal policy)
386     UPDATE action_trigger.event SET context_user = dest_usr WHERE context_user = src_usr;
387
388         -- acq.*
389         UPDATE acq.fund_allocation SET allocator = dest_usr WHERE allocator = src_usr;
390         UPDATE acq.lineitem SET creator = dest_usr WHERE creator = src_usr;
391         UPDATE acq.lineitem SET editor = dest_usr WHERE editor = src_usr;
392         UPDATE acq.lineitem SET selector = dest_usr WHERE selector = src_usr;
393         UPDATE acq.lineitem_note SET creator = dest_usr WHERE creator = src_usr;
394         UPDATE acq.lineitem_note SET editor = dest_usr WHERE editor = src_usr;
395         UPDATE acq.invoice SET closed_by = dest_usr WHERE closed_by = src_usr;
396         DELETE FROM acq.lineitem_usr_attr_definition WHERE usr = src_usr;
397
398         -- Update with a rename to avoid collisions
399         FOR renamable_row in
400                 SELECT id, name
401                 FROM   acq.picklist
402                 WHERE  owner = src_usr
403         LOOP
404                 suffix := ' (' || src_usr || ')';
405                 LOOP
406                         BEGIN
407                                 UPDATE  acq.picklist
408                                 SET     owner = dest_usr, name = name || suffix
409                                 WHERE   id = renamable_row.id;
410                         EXCEPTION WHEN unique_violation THEN
411                                 suffix := suffix || ' ';
412                                 CONTINUE;
413                         END;
414                         EXIT;
415                 END LOOP;
416         END LOOP;
417
418         UPDATE acq.picklist SET creator = dest_usr WHERE creator = src_usr;
419         UPDATE acq.picklist SET editor = dest_usr WHERE editor = src_usr;
420         UPDATE acq.po_note SET creator = dest_usr WHERE creator = src_usr;
421         UPDATE acq.po_note SET editor = dest_usr WHERE editor = src_usr;
422         UPDATE acq.purchase_order SET owner = dest_usr WHERE owner = src_usr;
423         UPDATE acq.purchase_order SET creator = dest_usr WHERE creator = src_usr;
424         UPDATE acq.purchase_order SET editor = dest_usr WHERE editor = src_usr;
425         UPDATE acq.claim_event SET creator = dest_usr WHERE creator = src_usr;
426
427         -- action.*
428         DELETE FROM action.circulation WHERE usr = src_usr;
429         UPDATE action.circulation SET circ_staff = dest_usr WHERE circ_staff = src_usr;
430         UPDATE action.circulation SET checkin_staff = dest_usr WHERE checkin_staff = src_usr;
431         UPDATE action.hold_notification SET notify_staff = dest_usr WHERE notify_staff = src_usr;
432         UPDATE action.hold_request SET fulfillment_staff = dest_usr WHERE fulfillment_staff = src_usr;
433         UPDATE action.hold_request SET requestor = dest_usr WHERE requestor = src_usr;
434         UPDATE action.hold_request SET canceled_by = dest_usr WHERE canceled_by = src_usr;
435         DELETE FROM action.hold_request WHERE usr = src_usr;
436         UPDATE action.in_house_use SET staff = dest_usr WHERE staff = src_usr;
437         UPDATE action.non_cat_in_house_use SET staff = dest_usr WHERE staff = src_usr;
438         DELETE FROM action.non_cataloged_circulation WHERE patron = src_usr;
439         UPDATE action.non_cataloged_circulation SET staff = dest_usr WHERE staff = src_usr;
440         DELETE FROM action.survey_response WHERE usr = src_usr;
441         UPDATE action.fieldset SET owner = dest_usr WHERE owner = src_usr;
442         DELETE FROM action.usr_circ_history WHERE usr = src_usr;
443         UPDATE action.curbside SET notes = NULL WHERE patron = src_usr;
444
445         -- actor.*
446         DELETE FROM actor.card WHERE usr = src_usr;
447         DELETE FROM actor.stat_cat_entry_usr_map WHERE target_usr = src_usr;
448         DELETE FROM actor.usr_privacy_waiver WHERE usr = src_usr;
449         DELETE FROM actor.usr_message WHERE usr = src_usr;
450
451         -- The following update is intended to avoid transient violations of a foreign
452         -- key constraint, whereby actor.usr_address references itself.  It may not be
453         -- necessary, but it does no harm.
454         UPDATE actor.usr_address SET replaces = NULL
455                 WHERE usr = src_usr AND replaces IS NOT NULL;
456         DELETE FROM actor.usr_address WHERE usr = src_usr;
457         DELETE FROM actor.usr_org_unit_opt_in WHERE usr = src_usr;
458         UPDATE actor.usr_org_unit_opt_in SET staff = dest_usr WHERE staff = src_usr;
459         DELETE FROM actor.usr_setting WHERE usr = src_usr;
460         DELETE FROM actor.usr_standing_penalty WHERE usr = src_usr;
461         UPDATE actor.usr_message SET title = 'purged', message = 'purged', read_date = NOW() WHERE usr = src_usr;
462         DELETE FROM actor.usr_message WHERE usr = src_usr;
463         UPDATE actor.usr_standing_penalty SET staff = dest_usr WHERE staff = src_usr;
464         UPDATE actor.usr_message SET editor = dest_usr WHERE editor = src_usr;
465
466         -- asset.*
467         UPDATE asset.call_number SET creator = dest_usr WHERE creator = src_usr;
468         UPDATE asset.call_number SET editor = dest_usr WHERE editor = src_usr;
469         UPDATE asset.call_number_note SET creator = dest_usr WHERE creator = src_usr;
470         UPDATE asset.copy SET creator = dest_usr WHERE creator = src_usr;
471         UPDATE asset.copy SET editor = dest_usr WHERE editor = src_usr;
472         UPDATE asset.copy_note SET creator = dest_usr WHERE creator = src_usr;
473
474         -- auditor.*
475         DELETE FROM auditor.actor_usr_address_history WHERE id = src_usr;
476         DELETE FROM auditor.actor_usr_history WHERE id = src_usr;
477         UPDATE auditor.asset_call_number_history SET creator = dest_usr WHERE creator = src_usr;
478         UPDATE auditor.asset_call_number_history SET editor  = dest_usr WHERE editor  = src_usr;
479         UPDATE auditor.asset_copy_history SET creator = dest_usr WHERE creator = src_usr;
480         UPDATE auditor.asset_copy_history SET editor  = dest_usr WHERE editor  = src_usr;
481         UPDATE auditor.biblio_record_entry_history SET creator = dest_usr WHERE creator = src_usr;
482         UPDATE auditor.biblio_record_entry_history SET editor  = dest_usr WHERE editor  = src_usr;
483
484         -- biblio.*
485         UPDATE biblio.record_entry SET creator = dest_usr WHERE creator = src_usr;
486         UPDATE biblio.record_entry SET editor = dest_usr WHERE editor = src_usr;
487         UPDATE biblio.record_note SET creator = dest_usr WHERE creator = src_usr;
488         UPDATE biblio.record_note SET editor = dest_usr WHERE editor = src_usr;
489
490         -- container.*
491         -- Update buckets with a rename to avoid collisions
492         FOR renamable_row in
493                 SELECT id, name
494                 FROM   container.biblio_record_entry_bucket
495                 WHERE  owner = src_usr
496         LOOP
497                 suffix := ' (' || src_usr || ')';
498                 LOOP
499                         BEGIN
500                                 UPDATE  container.biblio_record_entry_bucket
501                                 SET     owner = dest_usr, name = name || suffix
502                                 WHERE   id = renamable_row.id;
503                         EXCEPTION WHEN unique_violation THEN
504                                 suffix := suffix || ' ';
505                                 CONTINUE;
506                         END;
507                         EXIT;
508                 END LOOP;
509         END LOOP;
510
511         FOR renamable_row in
512                 SELECT id, name
513                 FROM   container.call_number_bucket
514                 WHERE  owner = src_usr
515         LOOP
516                 suffix := ' (' || src_usr || ')';
517                 LOOP
518                         BEGIN
519                                 UPDATE  container.call_number_bucket
520                                 SET     owner = dest_usr, name = name || suffix
521                                 WHERE   id = renamable_row.id;
522                         EXCEPTION WHEN unique_violation THEN
523                                 suffix := suffix || ' ';
524                                 CONTINUE;
525                         END;
526                         EXIT;
527                 END LOOP;
528         END LOOP;
529
530         FOR renamable_row in
531                 SELECT id, name
532                 FROM   container.copy_bucket
533                 WHERE  owner = src_usr
534         LOOP
535                 suffix := ' (' || src_usr || ')';
536                 LOOP
537                         BEGIN
538                                 UPDATE  container.copy_bucket
539                                 SET     owner = dest_usr, name = name || suffix
540                                 WHERE   id = renamable_row.id;
541                         EXCEPTION WHEN unique_violation THEN
542                                 suffix := suffix || ' ';
543                                 CONTINUE;
544                         END;
545                         EXIT;
546                 END LOOP;
547         END LOOP;
548
549         FOR renamable_row in
550                 SELECT id, name
551                 FROM   container.user_bucket
552                 WHERE  owner = src_usr
553         LOOP
554                 suffix := ' (' || src_usr || ')';
555                 LOOP
556                         BEGIN
557                                 UPDATE  container.user_bucket
558                                 SET     owner = dest_usr, name = name || suffix
559                                 WHERE   id = renamable_row.id;
560                         EXCEPTION WHEN unique_violation THEN
561                                 suffix := suffix || ' ';
562                                 CONTINUE;
563                         END;
564                         EXIT;
565                 END LOOP;
566         END LOOP;
567
568         DELETE FROM container.user_bucket_item WHERE target_user = src_usr;
569
570         -- money.*
571         DELETE FROM money.billable_xact WHERE usr = src_usr;
572         DELETE FROM money.collections_tracker WHERE usr = src_usr;
573         UPDATE money.collections_tracker SET collector = dest_usr WHERE collector = src_usr;
574
575         -- permission.*
576         DELETE FROM permission.usr_grp_map WHERE usr = src_usr;
577         DELETE FROM permission.usr_object_perm_map WHERE usr = src_usr;
578         DELETE FROM permission.usr_perm_map WHERE usr = src_usr;
579         DELETE FROM permission.usr_work_ou_map WHERE usr = src_usr;
580
581         -- reporter.*
582         -- Update with a rename to avoid collisions
583         BEGIN
584                 FOR renamable_row in
585                         SELECT id, name
586                         FROM   reporter.output_folder
587                         WHERE  owner = src_usr
588                 LOOP
589                         suffix := ' (' || src_usr || ')';
590                         LOOP
591                                 BEGIN
592                                         UPDATE  reporter.output_folder
593                                         SET     owner = dest_usr, name = name || suffix
594                                         WHERE   id = renamable_row.id;
595                                 EXCEPTION WHEN unique_violation THEN
596                                         suffix := suffix || ' ';
597                                         CONTINUE;
598                                 END;
599                                 EXIT;
600                         END LOOP;
601                 END LOOP;
602         EXCEPTION WHEN undefined_table THEN
603                 -- do nothing
604         END;
605
606         BEGIN
607                 UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr;
608         EXCEPTION WHEN undefined_table THEN
609                 -- do nothing
610         END;
611
612         -- Update with a rename to avoid collisions
613         BEGIN
614                 FOR renamable_row in
615                         SELECT id, name
616                         FROM   reporter.report_folder
617                         WHERE  owner = src_usr
618                 LOOP
619                         suffix := ' (' || src_usr || ')';
620                         LOOP
621                                 BEGIN
622                                         UPDATE  reporter.report_folder
623                                         SET     owner = dest_usr, name = name || suffix
624                                         WHERE   id = renamable_row.id;
625                                 EXCEPTION WHEN unique_violation THEN
626                                         suffix := suffix || ' ';
627                                         CONTINUE;
628                                 END;
629                                 EXIT;
630                         END LOOP;
631                 END LOOP;
632         EXCEPTION WHEN undefined_table THEN
633                 -- do nothing
634         END;
635
636         BEGIN
637                 UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr;
638         EXCEPTION WHEN undefined_table THEN
639                 -- do nothing
640         END;
641
642         BEGIN
643                 UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr;
644         EXCEPTION WHEN undefined_table THEN
645                 -- do nothing
646         END;
647
648         -- Update with a rename to avoid collisions
649         BEGIN
650                 FOR renamable_row in
651                         SELECT id, name
652                         FROM   reporter.template_folder
653                         WHERE  owner = src_usr
654                 LOOP
655                         suffix := ' (' || src_usr || ')';
656                         LOOP
657                                 BEGIN
658                                         UPDATE  reporter.template_folder
659                                         SET     owner = dest_usr, name = name || suffix
660                                         WHERE   id = renamable_row.id;
661                                 EXCEPTION WHEN unique_violation THEN
662                                         suffix := suffix || ' ';
663                                         CONTINUE;
664                                 END;
665                                 EXIT;
666                         END LOOP;
667                 END LOOP;
668         EXCEPTION WHEN undefined_table THEN
669         -- do nothing
670         END;
671
672         -- vandelay.*
673         -- Update with a rename to avoid collisions
674         FOR renamable_row in
675                 SELECT id, name
676                 FROM   vandelay.queue
677                 WHERE  owner = src_usr
678         LOOP
679                 suffix := ' (' || src_usr || ')';
680                 LOOP
681                         BEGIN
682                                 UPDATE  vandelay.queue
683                                 SET     owner = dest_usr, name = name || suffix
684                                 WHERE   id = renamable_row.id;
685                         EXCEPTION WHEN unique_violation THEN
686                                 suffix := suffix || ' ';
687                                 CONTINUE;
688                         END;
689                         EXIT;
690                 END LOOP;
691         END LOOP;
692
693     UPDATE vandelay.session_tracker SET usr = dest_usr WHERE usr = src_usr;
694
695     -- NULL-ify addresses last so other cleanup (e.g. circ anonymization)
696     -- can access the information before deletion.
697         UPDATE actor.usr SET
698                 active = FALSE,
699                 card = NULL,
700                 mailing_address = NULL,
701                 billing_address = NULL
702         WHERE id = src_usr;
703
704 END;
705 $$ LANGUAGE plpgsql;
706
707 COMMIT;
708