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