3 SELECT evergreen.upgrade_deps_block_check('1405', :eg_version);
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;
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);
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 $$
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
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;
34 DELETE FROM actor.card where usr = src_usr;
36 IF deactivate_cards THEN
37 UPDATE actor.card SET active = 'f' WHERE usr = src_usr;
39 UPDATE actor.card SET usr = dest_usr WHERE usr = src_usr;
44 DELETE FROM actor.usr_address WHERE usr = src_usr;
46 UPDATE actor.usr_address SET usr = dest_usr WHERE usr = src_usr;
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);
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);
64 -- For each *_bucket table: transfer every bucket belonging to src_usr
65 -- into the custody of dest_usr.
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.
74 FROM container.biblio_record_entry_bucket
77 suffix := ' (' || src_usr || ')';
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 || ' ';
93 FROM container.call_number_bucket
96 suffix := ' (' || src_usr || ')';
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 || ' ';
112 FROM container.copy_bucket
113 WHERE owner = src_usr
115 suffix := ' (' || src_usr || ')';
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 || ' ';
131 FROM container.user_bucket
132 WHERE owner = src_usr
134 suffix := ' (' || src_usr || ')';
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 || ' ';
148 UPDATE container.user_bucket_item SET target_user = dest_usr WHERE target_user = src_usr;
151 -- transfer queues the same way we transfer buckets (see above)
155 WHERE owner = src_usr
157 suffix := ' (' || src_usr || ')';
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 || ' ';
171 UPDATE vandelay.session_tracker SET usr = dest_usr WHERE usr = src_usr;
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;
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;
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;
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;
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;
203 -- transfer picklists the same way we transfer buckets (see above)
207 WHERE owner = src_usr
209 suffix := ' (' || src_usr || ')';
213 SET owner = dest_usr, name = name || suffix
214 WHERE id = picklist_row.id;
215 EXCEPTION WHEN unique_violation THEN
216 suffix := suffix || ' ';
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;
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;
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;
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.
248 UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr;
249 EXCEPTION WHEN undefined_table THEN
253 UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr;
254 EXCEPTION WHEN undefined_table THEN
258 UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr;
259 EXCEPTION WHEN undefined_table THEN
263 -- transfer folders the same way we transfer buckets (see above)
266 FROM reporter.template_folder
267 WHERE owner = src_usr
269 suffix := ' (' || src_usr || ')';
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 || ' ';
282 EXCEPTION WHEN undefined_table THEN
286 -- transfer folders the same way we transfer buckets (see above)
289 FROM reporter.report_folder
290 WHERE owner = src_usr
292 suffix := ' (' || src_usr || ')';
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 || ' ';
305 EXCEPTION WHEN undefined_table THEN
309 -- transfer folders the same way we transfer buckets (see above)
312 FROM reporter.output_folder
313 WHERE owner = src_usr
315 suffix := ' (' || src_usr || ')';
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 || ' ';
328 EXCEPTION WHEN undefined_table THEN
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)
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)),
343 COALESCE(pref_family_name, (SELECT pref_family_name FROM susr)),
345 COALESCE(pref_suffix, (SELECT pref_suffix FROM susr))
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 = (
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+'
360 ) SELECT STRING_AGG(kw.parts, ' ') FROM keywords kw
361 ) WHERE id = dest_usr;
363 -- Finally, delete the source user
364 PERFORM actor.usr_delete(src_usr,dest_usr);
369 CREATE OR REPLACE FUNCTION actor.usr_purge_data(
371 specified_dest_usr IN INTEGER
375 renamable_row RECORD;
379 IF specified_dest_usr IS NULL THEN
380 dest_usr := 1; -- Admin user on stock installs
382 dest_usr := specified_dest_usr;
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;
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;
398 -- Update with a rename to avoid collisions
402 WHERE owner = src_usr
404 suffix := ' (' || src_usr || ')';
408 SET owner = dest_usr, name = name || suffix
409 WHERE id = renamable_row.id;
410 EXCEPTION WHEN unique_violation THEN
411 suffix := suffix || ' ';
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;
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;
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;
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;
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;
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;
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;
491 -- Update buckets with a rename to avoid collisions
494 FROM container.biblio_record_entry_bucket
495 WHERE owner = src_usr
497 suffix := ' (' || src_usr || ')';
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 || ' ';
513 FROM container.call_number_bucket
514 WHERE owner = src_usr
516 suffix := ' (' || src_usr || ')';
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 || ' ';
532 FROM container.copy_bucket
533 WHERE owner = src_usr
535 suffix := ' (' || src_usr || ')';
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 || ' ';
551 FROM container.user_bucket
552 WHERE owner = src_usr
554 suffix := ' (' || src_usr || ')';
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 || ' ';
568 DELETE FROM container.user_bucket_item WHERE target_user = src_usr;
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;
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;
582 -- Update with a rename to avoid collisions
586 FROM reporter.output_folder
587 WHERE owner = src_usr
589 suffix := ' (' || src_usr || ')';
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 || ' ';
602 EXCEPTION WHEN undefined_table THEN
607 UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr;
608 EXCEPTION WHEN undefined_table THEN
612 -- Update with a rename to avoid collisions
616 FROM reporter.report_folder
617 WHERE owner = src_usr
619 suffix := ' (' || src_usr || ')';
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 || ' ';
632 EXCEPTION WHEN undefined_table THEN
637 UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr;
638 EXCEPTION WHEN undefined_table THEN
643 UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr;
644 EXCEPTION WHEN undefined_table THEN
648 -- Update with a rename to avoid collisions
652 FROM reporter.template_folder
653 WHERE owner = src_usr
655 suffix := ' (' || src_usr || ')';
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 || ' ';
668 EXCEPTION WHEN undefined_table THEN
673 -- Update with a rename to avoid collisions
677 WHERE owner = src_usr
679 suffix := ' (' || src_usr || ')';
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 || ' ';
693 UPDATE vandelay.session_tracker SET usr = dest_usr WHERE usr = src_usr;
695 -- NULL-ify addresses last so other cleanup (e.g. circ anonymization)
696 -- can access the information before deletion.
700 mailing_address = NULL,
701 billing_address = NULL