DBA Data[Home] [Help]

PACKAGE BODY: APPS.HR_DM_MASTER

Source


1 PACKAGE BODY hr_dm_master AS
2 /* $Header: perdmmas.pkb 120.0 2005/05/31 17:11:52 appldev noship $ */
3 
4 
5 /*-------------------------- PRIVATE ROUTINES ----------------------------*/
6 
7 -- ------------------------- controller_init ------------------------
8 -- Description: Various initialization processes are undertaken:
9 --  a) ensuring that data for the migration exists in hr_dm_migrations
10 --  b) entries in hr_dm_migration_requests are marked as inactive
11 --  c) r_migration_data is seeded with information about the migration
12 --  d) the migration count is incremented
13 --  e) the validity of the migration is checked
14 --  f) the migration status is set to started
15 --
16 --
17 --  Input Parameters
18 --        p_migration_id   - migration id
19 --
20 --        r_migration_data - record containing migration information
21 --
22 --        p_request_data   - concurrent request data (contains previous
23 --                           phase code - if it was a concurrent phase)
24 --
25 --
26 --  Output Parameters
27 --        r_migration_data - record containing migration information
28 --
29 --
30 -- ------------------------------------------------------------------------
31 
32 --
33 PROCEDURE controller_init(p_migration_id IN NUMBER,
34                           r_migration_data IN OUT
35                                              hr_dm_utility.r_migration_rec,
36                           p_request_data IN VARCHAR2) IS
37 --
38 
39 l_current_phase_status VARCHAR2(30);
40 l_migration_type VARCHAR2(30);
41 l_application_id NUMBER;
42 l_migration_id NUMBER;
43 l_database_name VARCHAR2(30);
44 l_source_database_name VARCHAR2(30);
45 l_destination_database_name VARCHAR2(30);
46 l_last_migrated_date DATE;
47 l_phase_flag VARCHAR2(1);
48 l_migration_count NUMBER;
49 l_business_group_id NUMBER;
50 l_valid_migration VARCHAR2(1);
51 e_fatal_error EXCEPTION;
52 l_fatal_error_message VARCHAR2(200);
53 l_database_location VARCHAR2(30);
54 l_phase_name VARCHAR2(30);
55 l_status VARCHAR2(30);
56 l_migration_date DATE;
57 
58 
59 CURSOR csr_migration IS
60   SELECT MIGRATION_ID, UPPER(SOURCE_DATABASE_INSTANCE),
61          UPPER(DESTINATION_DATABASE_INSTANCE),
62          MIGRATION_TYPE, APPLICATION_ID, MIGRATION_COUNT, BUSINESS_GROUP_ID,
63          STATUS
64     FROM hr_dm_migrations
65     WHERE (migration_id = p_migration_id);
66 
67 CURSOR csr_migration_request IS
68   SELECT MAX(creation_date)
69     FROM hr_dm_migration_requests
70     WHERE (migration_id = p_migration_id);
71 
72 
73 CURSOR csr_database IS
74   SELECT UPPER(name)
75     FROM v$database;
76 
77 --
78 BEGIN
79 --
80 
81 hr_dm_utility.message('ROUT','entry:hr_dm_master.controller_init', 5);
82 hr_dm_utility.message('PARA','(p_migration_id - ' || p_migration_id ||
83                       ')(r_migration_data - record' ||
84                       ')(p_request_data - ' || p_request_data || ')', 10);
85 
86 
87 -- identify the migration type, current database and application id
88 OPEN csr_migration;
89 LOOP
90   FETCH csr_migration INTO l_migration_id, l_source_database_name,
91                            l_destination_database_name,
92                            l_migration_type, l_application_id,
93                            l_migration_count,
94                            l_business_group_id, l_status;
95   EXIT WHEN csr_migration%NOTFOUND;
96 END LOOP;
97 CLOSE csr_migration;
98 
99 -- raise error if no matching row in hr_dm_migrations
100 IF (l_migration_id IS NULL) THEN
101   l_fatal_error_message := 'No row identified in HR_DM_MIGRATIONS!';
102   RAISE e_fatal_error;
103 END IF;
104 
105 
106 -- set all the enabled flags to N for the current migration_request_id
107 -- except for the current run of the migration
108 --  (non-paused)
109 IF (p_request_data IS NULL) THEN
110   OPEN csr_migration_request;
111   FETCH csr_migration_request INTO l_migration_date;
112   CLOSE csr_migration_request;
113 
114   UPDATE hr_dm_migration_requests
115     SET enabled_flag = 'N'
116       WHERE ((migration_id = p_migration_id)
117         AND (creation_date <> l_migration_date));
118 
119   COMMIT;
120 
121   END IF;
122 
123 
124 OPEN csr_database;
125 LOOP
126   FETCH csr_database INTO l_database_name;
127   EXIT WHEN csr_database%NOTFOUND;
128 END LOOP;
129 CLOSE csr_database;
130 
131 IF (l_database_name = l_destination_database_name) THEN
132   l_database_location := 'D';
133 END IF;
134 IF (l_database_name = l_source_database_name) THEN
135   l_database_location := 'S';
136 END IF;
137 
138 -- seed data into record
139 r_migration_data.migration_id := p_migration_id;
140 r_migration_data.migration_type  := l_migration_type;
141 r_migration_data.database_location  := l_database_location;
142 r_migration_data.application_id  := l_application_id;
143 r_migration_data.business_group_id  := l_business_group_id;
144 r_migration_data.source_database_instance := l_source_database_name;
145 r_migration_data.destination_database_instance :=
146                                         l_destination_database_name;
147 r_migration_data.last_migration_date  :=
148                            hr_dm_business.last_migration_date(
149                                                     r_migration_data);
150 
151 -- increment migration count in hr_dm_migrations (non-paused)
152 IF (p_request_data IS NULL) THEN
153   UPDATE hr_dm_migrations
154     SET migration_count = l_migration_count+1
155     WHERE migration_id = p_migration_id;
156   COMMIT;
157 END IF;
158 
159 -- check if migration is valid / warning
160 -- (first run only)
161 IF (p_request_data IS NULL) THEN
162   l_valid_migration := hr_dm_business.validate_migration(r_migration_data);
163   IF (l_valid_migration = 'E') THEN
164 -- raise error
165     l_fatal_error_message := 'Invalid migration - business rule broken';
166     hr_dm_utility.update_migrations(p_new_status => 'E',
167                                     p_id => p_migration_id);
168     RAISE e_fatal_error;
169   END IF;
170 END IF;
171 
172 -- update status of migration to started (un-paused)
173 IF (NVL(p_request_data, '?') = '?') THEN
174   hr_dm_utility.update_migrations(p_new_status => 'S',
175                                   p_id => p_migration_id);
176 END IF;
177 
178 
179 hr_dm_utility.message('INFO','Main controller initialized', 15);
180 hr_dm_utility.message('SUMM','Main controller initialized', 20);
181 hr_dm_utility.message('ROUT','exit:hr_dm_master.controller_init', 25);
182 hr_dm_utility.message('PARA','(none)', 30);
183 
184 
185 
186 -- error handling
187 EXCEPTION
188 WHEN e_fatal_error THEN
189   hr_dm_utility.error(SQLCODE,'hr_dm_range.main_controller',
190                       l_fatal_error_message,'R');
191   report_error(l_phase_name, p_migration_id,
192                l_fatal_error_message ||
193                ' in hr_dm_master.main_controller', 'M');
194   RAISE;
195 WHEN OTHERS THEN
196   hr_dm_utility.error(SQLCODE,'hr_dm_master.main_controller',
197                       '(none)','R');
198   report_error(l_phase_name, p_migration_id,
199                'Untrapped error in hr_dm_master.main_controller', 'M');
200   RAISE;
201 
202 
203 --
204 END controller_init;
205 --
206 
207 -- ------------------------- insert_request ------------------------
208 -- Description: Inserts the details of a concurrent manager request into
209 -- the table hr_dm_migration_requests.
210 --
211 --
212 --  Input Parameters
213 --        p_phase          - phase code
214 --
215 --        p_request_id     - concurrent manager request id
216 --
217 --        p_migration_id   - migration id
218 --
219 --        p_phase_id       - for a slave request
220 --
221 --        p_phase_item_id  - for a slave request from a slave
222 --
223 --
224 --  Output Parameters
225 --        <none>
226 --
227 --
228 -- ------------------------------------------------------------------------
229 
230 
231 --
232 PROCEDURE insert_request(p_phase IN VARCHAR2,
233                          p_request_id IN NUMBER,
234                          p_master_slave IN VARCHAR2 DEFAULT 'S',
235                          p_migration_id IN NUMBER,
236                          p_phase_id IN NUMBER DEFAULT NULL,
237                          p_phase_item_id IN NUMBER DEFAULT NULL) IS
238 --
239 
240 --
241 BEGIN
242 --
243 
244 hr_dm_utility.message('ROUT','entry:hr_dm_master.insert_request', 5);
245 hr_dm_utility.message('PARA','(p_phase - ' || p_phase ||
246                       ')(p_request_id - ' || p_request_id ||
247                       ')(p_master_slave - ' || p_master_slave ||
248                       ')(p_migration_id - ' || p_migration_id ||
249                       ')(p_phase_id - ' || p_phase_id ||
250                       ')(p_phase_item_id - ' || p_phase_item_id || ')', 10);
251 
252 
253 INSERT INTO hr_dm_migration_requests (migration_request_id,
254                                       migration_id,
255                                       phase_id,
256                                       phase_item_id,
257                                       request_id,
258                                       enabled_flag,
259                                       master_slave,
260                                       last_updated_by,
261                                       last_update_date,
262                                       last_update_login,
263                                       creation_date,
264                                       created_by)
265   SELECT hr_dm_migration_requests_s.nextval,
266          p_migration_id,
267          p_phase_id,
268          p_phase_item_id,
269          p_request_id,
270          'Y',
271          p_master_slave,
272          1,
273          sysdate,
274          1,
275          sysdate,
276          1
277     FROM sys.dual
278     WHERE NOT EXISTS
279       (SELECT NULL FROM hr_dm_migration_requests
280          WHERE request_id = p_request_id);
281 
282 COMMIT;
283 
284 hr_dm_utility.message('INFO','Inserted into hr_dm_migration_requests', 15);
285 hr_dm_utility.message('SUMM','Inserted into hr_dm_migration_requests', 20);
286 hr_dm_utility.message('ROUT','exit:hr_dm_master.insert_request', 25);
287 hr_dm_utility.message('PARA','(none)', 30);
288 
289 -- error handling
290 EXCEPTION
291 WHEN OTHERS THEN
292   hr_dm_utility.error(SQLCODE,'hr_dm_master.insert_request','(none)','R');
293   RAISE;
294 
295 
296 --
297 END insert_request;
298 --
299 
300 
301 -- ------------------------- spawn_slaves ------------------------
302 -- Description: The appropriate concurrent program for the current phase
303 -- is spawned and details recorded (by calling insert_request).
304 --
305 --
306 --  Input Parameters
307 --        p_current_phase  - phase code
308 --
309 --        r_migration_data - record containing migration information
310 --
311 --
312 --  Output Parameters
313 --        <none>
314 --
315 --
316 -- ------------------------------------------------------------------------
317 
318 --
319 PROCEDURE spawn_slaves(p_current_phase IN VARCHAR2,
320                        r_migration_data IN hr_dm_utility.r_migration_rec) IS
321 --
322 
323 l_counter NUMBER;
324 l_request_id NUMBER;
325 e_fatal_error EXCEPTION;
326 l_fatal_error_message VARCHAR2(200);
327 l_slave_program VARCHAR2(30);
328 l_phase_id NUMBER;
329 l_threads NUMBER;
330 
331 
332 --
333 BEGIN
334 --
335 
336 hr_dm_utility.message('ROUT','entry:hr_dm_master.spawn_slaves', 5);
337 hr_dm_utility.message('PARA','(p_current_phase - ' || p_current_phase ||
338                       ')(r_migration_data - record)', 10);
339 
340 
341 -- set up name for appropriate concurrent slave
342 l_slave_program := 'HRDMSLV' || p_current_phase;
343 
344 -- get the current phase_id
345 l_phase_id := hr_dm_utility.get_phase_id(p_current_phase,
346                                          r_migration_data.migration_id);
347 
348 -- find the number of threads to use
349 l_threads := hr_dm_utility.number_of_threads(
350                                     r_migration_data.business_group_id);
351 -- only single thread for UP phase
352 IF (p_current_phase = 'UP') THEN
353   l_threads := 1;
354 END IF;
355 
356 -- only single thread for UA phase
357 IF (p_current_phase = 'UA') THEN
358   l_threads := 1;
359 END IF;
360 
361 -- only single thread for C phase
362 IF (p_current_phase = 'C') THEN
363   l_threads := 1;
364 END IF;
365 
366 -- set current processing
367 hr_dm_utility.set_process(l_threads || ' slaves',
368                           p_current_phase,
369                           r_migration_data.migration_id);
370 
371 
372 FOR l_counter IN 1..l_threads LOOP
373   hr_dm_utility.message('INFO','Spawning slave #' || l_counter, 16);
374 
375 
376   l_request_id := fnd_request.submit_request(
377                       application => 'PER',
378                       program     => l_slave_program,
379                       sub_request => TRUE,
380                       argument1 => TO_CHAR(r_migration_data.migration_id),
381                       argument2 => 'Y',
382                       argument3 =>
383                             TO_CHAR(r_migration_data.last_migration_date),
384                       argument4 => TO_CHAR(l_counter));
385 
386 
387   -- update table hr_dm_migration_requests
388   insert_request(p_phase => p_current_phase,
389                  p_request_id => l_request_id,
390                  p_master_slave => 'S',
391                  p_migration_id => r_migration_data.migration_id,
392                  p_phase_id => l_phase_id);
393 
394   COMMIT;
395   hr_dm_utility.message('INFO','Slave request ID#' || l_request_id, 17);
396   IF (l_request_id = 0) THEN
397       l_fatal_error_message := 'Unable to start slave process';
398       report_error(p_current_phase, r_migration_data.migration_id,
399                    l_fatal_error_message, 'P');
400       RAISE e_fatal_error;
401   END IF;
402 END LOOP;
403 
404 hr_dm_utility.message('INFO','Spawned slaves', 15);
405 hr_dm_utility.message('SUMM','Spawned slaves', 20);
406 hr_dm_utility.message('ROUT','exit:hr_dm_master.spawn_slaves', 25);
407 hr_dm_utility.message('PARA','(none)', 30);
408 
409 
410 
411 -- error handling
412 EXCEPTION
413 WHEN e_fatal_error THEN
414   hr_dm_utility.error(SQLCODE,'hr_dm_master.spawn_slaves',
415                       l_fatal_error_message,'R');
416   report_error(p_current_phase, r_migration_data.migration_id,
417                'Error in hr_dm_master.spawn_slaves', 'P');
418   RAISE;
419 WHEN OTHERS THEN
420   hr_dm_utility.error(SQLCODE,'hr_dm_master.spawn_slaves','(none)','R');
421   report_error(p_current_phase, r_migration_data.migration_id,
422                'Untrapped error in hr_dm_master.spawn_slaves', 'P');
423   RAISE;
424 
425 --
426 END spawn_slaves;
427 --
428 
429 -- ------------------------- slave_status ------------------------
430 -- Description: The status of all slaves submitted for the passed phase
431 -- are checked to ensure that all have completed normally, otherwise
432 -- the return value is set to Y.
433 --
434 --
435 --  Input Parameters
436 --        p_current_phase  - phase code
437 --
438 --        r_migration_data - record containing migration information
439 --
440 --
441 --  Return Values
442 --        slave status - Y = one or more slaves errored
443 --                       N = no slaves errored
444 --
445 --
446 -- ------------------------------------------------------------------------
447 
448 --
449 FUNCTION slave_status(p_current_phase IN VARCHAR2,
450                       r_migration_data IN hr_dm_utility.r_migration_rec)
451                      RETURN VARCHAR2 IS
452 --
453 
454 l_slave_status VARCHAR2(1);
455 l_slave_error VARCHAR2(1) := 'N';
456 l_call_status BOOLEAN;
457 l_phase VARCHAR2(30);
458 l_status VARCHAR2(30);
459 l_dev_phase VARCHAR2(30);
460 l_dev_status VARCHAR2(30);
461 l_message VARCHAR2(240);
462 l_request_id NUMBER;
463 l_phase_id NUMBER;
464 
465 CURSOR csr_requests IS
466   SELECT request_id
467     FROM hr_dm_migration_requests
468     WHERE ((phase_id = l_phase_id)
469       AND (master_slave = 'S')
470       AND (enabled_flag = 'Y'));
471 
472 
473 --
474 BEGIN
475 --
476 
477 hr_dm_utility.message('ROUT','entry:hr_dm_master.slave_status', 5);
478 hr_dm_utility.message('PARA','(p_current_phase - ' || p_current_phase ||
479                   ')(r_migration_data - record)', 10);
480 
481 -- get the current phase_id
482 l_phase_id := hr_dm_utility.get_phase_id(p_current_phase,
483                                          r_migration_data.migration_id);
484 
485 -- check if a slave has errored
486 OPEN csr_requests;
487 LOOP
488   FETCH csr_requests INTO l_request_id;
489   EXIT WHEN csr_requests%NOTFOUND;
490 
491   l_call_status := fnd_concurrent.get_request_status(l_request_id, '', '',
492                                 l_phase, l_status, l_dev_phase,
493                                 l_dev_status, l_message);
494 -- make sure that each slave is complete and normal, if not then log
495   IF ( NOT( (l_dev_phase = 'COMPLETE') AND (l_dev_status = 'NORMAL') )) THEN
496     l_slave_error := 'Y';
497   END IF;
498 
499 END LOOP;
500 CLOSE csr_requests;
501 
502 
503 hr_dm_utility.message('INFO','Slave status request', 15);
504 hr_dm_utility.message('SUMM','Slave status request', 20);
505 hr_dm_utility.message('ROUT','exit:hr_dm_master.spawn_slaves', 25);
506 hr_dm_utility.message('PARA','(l_slave_error - ' || l_slave_error ||
507                       ')', 30);
508 
509 
510 RETURN(l_slave_error);
511 
512 -- error handling
513 EXCEPTION
514 WHEN OTHERS THEN
515   hr_dm_utility.error(SQLCODE,'hr_dm_master.slave_status','(none)','R');
516   report_error(p_current_phase, r_migration_data.migration_id,
517                'Untrapped error in hr_dm_master.slave_status', 'P');
518   RAISE;
519 
520 --
521 END slave_status;
522 --
523 
524 -- ------------------------- report_error ------------------------
525 -- Description: Reports the fact that an error has occurred and updates
526 -- the status of the phase / migration as appropriate.
527 --
528 --
529 --  Input Parameters
530 --        p_current_phase - phase code
531 --
532 --        p_migration     - migration id
533 --
534 --        p_error_message - error text
535 --
536 --        p_stage         - P = error occurred in a phase
537 --                          M = error occured in migration
538 --
539 --
540 --  Output Parameters
541 --        <none>
542 --
543 --
544 -- ------------------------------------------------------------------------
545 
546 --
547 PROCEDURE report_error(p_current_phase IN VARCHAR2,
548                        p_migration IN NUMBER,
549                        p_error_message IN VARCHAR2,
550                        p_stage IN VARCHAR2
551                        ) IS
552 --
553 
554 --
555 BEGIN
556 --
557 
558 hr_dm_utility.message('ROUT','entry:hr_dm_master.report_error', 5);
559 hr_dm_utility.message('PARA','(p_current_phase - ' || p_current_phase ||
560                   ')(p_migration - ' || p_migration ||
561                   ')(p_error_message - ' || p_error_message ||
562                   ')(p_stage - ' || p_stage || ')', 10);
563 
564 
565 -- update status to show error (E)
566 -- update approriate phase, migration, etc.
567 IF (p_stage = 'P') THEN
568   hr_dm_utility.update_phases(p_new_status => 'E',
569                               p_id => hr_dm_utility.get_phase_id(
570                                              p_current_phase, p_migration));
571 END IF;
572 
573 IF (p_stage = 'M') THEN
574   hr_dm_utility.update_migrations(p_new_status => 'E', p_id => p_migration);
575 END IF;
576 
577 
578 hr_dm_utility.message('INFO','Error reported', 15);
579 hr_dm_utility.message('SUMM','Error reported', 20);
580 hr_dm_utility.message('ROUT','exit:hr_dm_master.report_error', 25);
581 hr_dm_utility.message('PARA','(none)', 30);
582 
583 
584 --
585 END report_error;
586 --
587 
588 -- ------------------------- work_required ------------------------
589 -- Description: A check is made to see if for the phase passed if there
590 -- are any phase items which do not have a status of C. If all have the
591 -- status C then the phase is marked as completed. Where a phase links
592 -- to migration ranges then these are also checked to see if for a
593 -- phase item that there are ranges to process.
594 --
595 --
596 --  Input Parameters
597 --        p_current_phase  - phase code
598 --
599 --        r_migration_data - record containing migration information
600 --
601 --
602 --  Return Values
603 --        work required - Y = phase items to process
604 --                        N = phase items to process
605 --
606 --
607 -- ------------------------------------------------------------------------
608 
609 --
610 FUNCTION work_required(p_current_phase IN VARCHAR2,
611                        r_migration_data IN hr_dm_utility.r_migration_rec)
612                       RETURN VARCHAR2 IS
613 --
614 
615 l_work VARCHAR2(1);
616 l_phase_id NUMBER;
617 l_range_phase_id NUMBER;
618 l_required NUMBER;
619 l_phase_item_id NUMBER;
620 l_group_id NUMBER;
621 
622 CURSOR csr_phase_items IS
623   SELECT NULL
624     FROM hr_dm_phase_items
625     WHERE phase_id = l_phase_id
626       AND status <> 'C';
627 
628 CURSOR csr_ddp_pi IS
629   SELECT phase_item_id, group_id
630     FROM hr_dm_phase_items
631     WHERE phase_id = l_phase_id;
632 
633 CURSOR csr_mig_ranges IS
634   SELECT rpi.phase_item_id
635     FROM hr_dm_phase_items rpi,
636          hr_dm_migration_ranges mr
637     WHERE rpi.group_id = l_group_id
638       AND rpi.phase_id = l_range_phase_id
639       AND rpi.phase_item_id = mr.phase_item_id
640       AND mr.status <> 'C';
641 
642 
643 --
644 BEGIN
645 --
646 
647 hr_dm_utility.message('ROUT','entry:hr_dm_master.work_required', 5);
648 hr_dm_utility.message('PARA','(p_current_phase - ' || p_current_phase ||
649                       ')(r_migration_data - record)', 10);
650 
651 -- get the current phase_id
652 l_phase_id := hr_dm_utility.get_phase_id(p_current_phase,
653                                          r_migration_data.migration_id);
654 
655 l_work := 'Y';
656 
657 -- check if any phase items to process (not DP or D phases)
658 IF (p_current_phase IN ('G', 'R', 'DA', 'UA', 'UP', 'C')) THEN
659   OPEN csr_phase_items;
660   FETCH csr_phase_items INTO l_required;
661   IF (csr_phase_items%NOTFOUND) THEN
662     hr_dm_utility.message('INFO','No work required for phase ' ||
663                           p_current_phase, 11);
664     l_work := 'N';
665     hr_dm_utility.update_phases(p_new_status => 'C',
666                                 p_id => l_phase_id);
667   END IF;
668   CLOSE csr_phase_items;
669 END IF;
670 
671 
672 -- check phase items for DP or D phases to see if any migration ranges
673 -- to process
674 IF (p_current_phase IN ('DP', 'D')) THEN
675   hr_dm_utility.message('INFO','checking DP/D - ' || p_current_phase, 5);
676 -- get the range phase_id
677   l_range_phase_id := hr_dm_utility.get_phase_id('R',
678                                             r_migration_data.migration_id);
679   hr_dm_utility.message('INFO','l_range_phase_id - ' || l_range_phase_id, 5);
680 -- find phase_item_id for D/DP phase
681   OPEN csr_ddp_pi;
682   LOOP
683     FETCH csr_ddp_pi INTO l_phase_item_id, l_group_id;
684 hr_dm_utility.message('INFO','l_phase_item_id - ' || l_phase_item_id, 5);
685 hr_dm_utility.message('INFO','l_group_id - ' || l_group_id, 5);
686     EXIT WHEN csr_ddp_pi%NOTFOUND;
687 
688 -- see if any migration ranges to process for this phase_item_id
689     OPEN csr_mig_ranges;
690     FETCH csr_mig_ranges INTO l_required;
691 hr_dm_utility.message('INFO','l_required - ' || l_required, 5);
692     IF (csr_mig_ranges%NOTFOUND) THEN
693 -- mark phase item as started and then complete to ensure that
694 -- the start and end times are set
695     hr_dm_utility.message('INFO','No work required for group ' ||
696                           l_group_id, 12);
697 
698       hr_dm_utility.update_phase_items(p_new_status => 'S',
699                                        p_id => l_phase_item_id);
700       hr_dm_utility.update_phase_items(p_new_status => 'C',
701                                        p_id => l_phase_item_id);
702     END IF;
703     CLOSE csr_mig_ranges;
704 
705   END LOOP;
706   CLOSE csr_ddp_pi;
707 
708 -- see if any phase items to process
709 -- ie if csr_ddp_pi does not find any phase items
710   IF (l_phase_item_id IS NULL) THEN
711     hr_dm_utility.message('INFO','No work required for phase ' ||
712                           p_current_phase, 13);
713     l_work := 'N';
714     hr_dm_utility.update_phases(p_new_status => 'C',
715                                 p_id => l_phase_id);
716   END IF;
717 
718 -- see if phase is complete
719   IF (hr_dm_utility.get_phase_status(p_current_phase,
720                                  r_migration_data.migration_id) = 'C') THEN
721     l_work := 'N';
722   END IF;
723 
724 END IF;
725 
726 
727 hr_dm_utility.message('INFO','Check work required for phase', 15);
728 hr_dm_utility.message('SUMM','Check work required for phase', 20);
729 hr_dm_utility.message('ROUT','exit:hr_dm_master.work_required', 25);
730 hr_dm_utility.message('PARA','(l_work - ' || l_work || ')', 30);
731 
732 RETURN(l_work);
733 
734 -- error handling
735 EXCEPTION
736 WHEN OTHERS THEN
737   hr_dm_utility.error(SQLCODE,'hr_dm_master.work_required','(none)','R');
738   report_error(p_current_phase, r_migration_data.migration_id,
739                'Untrapped error in hr_dm_master.work_required', 'P');
740   RAISE;
741 
742 --
743 END work_required;
744 --
745 
746 
747 
748 -- ------------------------------- master ------------------------------
749 -- Description: This procedure calls the code appropriate for a phase
750 -- which is processed by multiple threads. There are two paths through
751 -- the code, dependent upon if the procedure is called at the start of
752 -- a phase or after the main controller has been awoken after the slaves
753 -- have finished processing. This is determined by examining the
754 -- concurrent request data which will contain the phase code for a
755 -- re-awoken phase and null for a first run.
756 --
757 -- On a first run (l_request_data = null) the status of the previous phase
758 -- is checked to ensure that it has completed. If not then the migration
759 -- status is set to error and the procedure exits.
760 --
761 -- A check is made to see if the current phase has either started or errored
762 -- in which case a rollback of the phase (if applicable) is performed.
763 --
764 -- The status of the phase is set to started and any phase specific
765 -- pre-processing code is called.
766 --
767 -- A check is made to see if there is any work to be performed by the phase
768 -- if so, slaves are spawned to perform the work and the main controller
769 -- is paused.
770 --
771 --
772 --
773 -- On a non-first run (l_request_data <> null), the request data is first
774 -- set to ? (equivelent to null) the status of the current phase
775 -- is checked to ensure that it has completed. If not then the migration
776 -- status is set to error and the procedure exits.
777 --
778 -- A check is made of the status of each slave and if any have not completed
779 -- normally then a warning message is logged.
780 --
781 -- Any phase specific post-processing code is called.
782 --
783 --
784 --
785 --  Input Parameters
786 --        p_current_phase  - phase code
787 --
788 --        p_previous_phase - phase code
789 --
790 --        r_migration_data - migration record
791 --
792 --
793 --  Output Parameters
794 --        <none>
795 --
796 --
797 -- ------------------------------------------------------------------------
798 
799 --
800 PROCEDURE master(p_current_phase IN VARCHAR2,
801                  p_previous_phase IN VARCHAR2,
802                  r_migration_data IN hr_dm_utility.r_migration_rec) IS
803 --
804 
805 l_current_phase_status VARCHAR2(30);
806 e_fatal_error EXCEPTION;
807 l_fatal_error_message VARCHAR2(200);
808 l_request_data VARCHAR2(30);
809 l_dummy VARCHAR2(1);
810 
811 
812 --
813 BEGIN
814 --
815 
816 hr_dm_utility.message('ROUT','entry:hr_dm_master.master', 5);
817 hr_dm_utility.message('PARA','(p_current_phase - ' || p_current_phase ||
818                   ')(p_previous_phase - ' || p_previous_phase ||
819                   ')(r_migration_data - record)', 10);
820 
821 -- see if this is the first run? (l_request_data = NULL or '?')
822 -- or
823 -- is it a restart after slaves have finished? (l_request_data =
824 --                                                       paused phase code)
825 l_request_data := fnd_conc_global.request_data;
826 
827 hr_dm_utility.message('INFO','l_request_data ' || l_request_data, 11);
828 IF (NVL(l_request_data, '?') = '?') THEN
829 -- first run processing...
830 
831 hr_dm_utility.message('INFO','First run processing (pre-pause)', 12);
832 
833 -- get status of previous phase, is previous phase completed?
834 -- for the first phase there is no previous phase, so check for
835 -- a NULL previous to bypass this check
836   IF ((hr_dm_utility.get_phase_status(p_previous_phase,
837                                       r_migration_data.migration_id) <> 'C')
838        AND (p_previous_phase IS NOT NULL) ) THEN
839     l_fatal_error_message := 'Previous phase has not completed';
840     report_error(p_current_phase, r_migration_data.migration_id,
841                  l_fatal_error_message, 'P');
842     RAISE e_fatal_error;
843   END IF;
844 
845 -- get status of current phase
846   l_current_phase_status := hr_dm_utility.get_phase_status(p_current_phase,
847                               r_migration_data.migration_id);
848 
849 -- is phase complete?
850   IF (l_current_phase_status <> 'C') THEN
851 -- do we need to explicitly rollback using rollback utility?
852     IF ( (l_current_phase_status IN('S', 'E')) AND
853          (p_current_phase IN('I', 'G', 'R', 'DP', 'DA', 'UA',
854                              'UP', 'C', 'D')) ) THEN
855       hr_dm_utility.rollback(p_phase => p_current_phase,
856                              p_masterslave => 'MASTER',
857                              p_migration_id =>
858                                           r_migration_data.migration_id);
859     END IF;
860 
861 -- update status to started
862     hr_dm_utility.update_phases(p_new_status => 'S',
863                               p_id => hr_dm_utility.get_phase_id(
864                                             p_current_phase,
865                                             r_migration_data.migration_id));
866     COMMIT;
867 
868 
869 -- call phase specific pre-processing code
870 
871 -- generate phase
872 -- create dummy hr_dmv views to avoid compilation errors
873   IF (p_current_phase = 'G') THEN
874     hr_dm_utility.set_process('Pre-processing',
875                               p_current_phase,
876                               r_migration_data.migration_id);
877     hr_dm_library.create_stub_views(r_migration_data.migration_id);
878   END IF;
879 
880 
881 
882 -- delete phase
883 -- set current processing
884   IF (p_current_phase = 'D') THEN
885     hr_dm_utility.set_process('Pre-processing',
886                               p_current_phase,
887                               r_migration_data.migration_id);
888     hr_dm_delete.set_active(r_migration_data.migration_id);
889     hr_dm_delete.pre_delete_process(r_migration_data);
890   END IF;
891 
892 
893 -- spawn off slaves if work to be done
894   IF (work_required(p_current_phase, r_migration_data) = 'Y') THEN
895       spawn_slaves(p_current_phase, r_migration_data);
896 
897 -- pause master whilst slaves process data...
898 -- set request data to indicate paused phase
899       fnd_conc_global.set_req_globals(conc_status => 'PAUSED',
900                                       request_data => p_current_phase);
901 
902   END IF;
903 
904 
905 
906 
907   END IF;
908 
909 ELSE
910 -- processing after being woken up
911 hr_dm_utility.message('INFO','Unpaused processing', 13);
912 -- set request data to indicate un-paused phase
913   fnd_conc_global.set_req_globals(request_data => '?');
914 
915 
916 -- first force check for all required work
917   l_dummy := work_required(p_current_phase, r_migration_data);
918 
919 -- get status of current phase
920   l_current_phase_status := hr_dm_utility.get_phase_status(p_current_phase,
921                                              r_migration_data.migration_id);
922 
923 -- is it completed?
924   IF (l_current_phase_status <> 'C') THEN
925     l_fatal_error_message := 'Current phase has not completed';
926     report_error(p_current_phase, r_migration_data.migration_id,
927                  l_fatal_error_message, 'P');
928     RAISE e_fatal_error;
929   END IF;
930 
931 -- has any slave errored?
932 -- if so, add warning message to log
933   IF (slave_status(p_current_phase, r_migration_data) = 'Y') THEN
934     hr_dm_utility.message('INFO', 'Warning - ' || p_current_phase ||
935                           ' phase slave process errored', 13);
936   END IF;
937 
938 -- call phase specific post processing code
939   IF (p_current_phase = 'G') THEN
940 -- set current processing
941     hr_dm_utility.set_process('Post-processing',
942                               p_current_phase,
943                               r_migration_data.migration_id);
944     hr_dm_gen_main.post_generate_validate(r_migration_data.migration_id);
945   END IF;
946 
947   IF (p_current_phase = 'C') THEN
948 -- set current processing
949     hr_dm_utility.set_process('Post-processing',
950                               p_current_phase,
951                               r_migration_data.migration_id);
952     hr_dm_cleanup.post_cleanup_process(r_migration_data);
953   END IF;
954 
955 
956 
957   IF (p_current_phase = 'UP') THEN
958 -- update flexfield information
959 -- for FW and A migrations only
960     IF (r_migration_data.migration_type IN ('FW','A')) THEN
961 -- Set the variable so as to disable the trigger on the table.
962       hr_general.g_data_migrator_mode := 'Y';
963       hr_dm_aol_up.post_aol_process(r_migration_data.migration_id);
964     END IF;
965 -- flush BEN_COMP_OBJ_CACHE
966 -- only for FW and A migrations for OAB product (id=805)
967 -- commented out - manual step
968 /*
969     IF (r_migration_data.migration_type IN ('FW','A'))
970       AND (r_migration_data.application_id = 805) THEN
971 -- Set the variable so as to disable the trigger on the table.
972       ben_comp_object_list.flush_multi_session_cache
973         (p_business_group_id => r_migration_data.business_group_id);
974     END IF;
975 */
976   END IF;
977 
978 
979 END IF;
980 
981 hr_dm_utility.message('INFO','Master concurrent program', 15);
982 hr_dm_utility.message('SUMM','Master concurrent program', 20);
983 hr_dm_utility.message('ROUT','exit:hr_dm_master.master', 25);
984 hr_dm_utility.message('PARA','(none)', 30);
985 
986 
987 
988 -- error handling
989 EXCEPTION
990 WHEN e_fatal_error THEN
991   hr_dm_utility.error(SQLCODE,'hr_dm_range.master',
992                       l_fatal_error_message,'R');
993   report_error(p_current_phase, r_migration_data.migration_id,
994               'Untrapped error in hr_dm_master.master', 'P');
995   RAISE;
996 WHEN OTHERS THEN
997   hr_dm_utility.error(SQLCODE,'hr_dm_master.master','(none)','R');
998   report_error(p_current_phase, r_migration_data.migration_id,
999               'Untrapped error in hr_dm_master.master', 'P');
1000   RAISE;
1001 --
1002 END master;
1003 --
1004 
1005 
1006 
1007 
1008 
1009 
1010 /*---------------------------- PUBLIC ROUTINES --------------------------*/
1011 
1012 -- ------------------------- main_controller ------------------------
1013 -- Description: This is the main controller for the DM which is called
1014 -- from the DM UI. It calls the required phases for the migration.
1015 --
1016 -- A check is made to see if the code is running for the first time or has
1017 -- been re-awoken.
1018 --
1019 -- The initialization code is called to set up various details (see the
1020 -- controller_init procedure).
1021 --
1022 -- The next phase to be process is found using the hr_dm_phase_rules table
1023 -- and the appropriate single or multi-threaded code is called.
1024 --
1025 -- If a multi-threaded process has spawned slaves then the main controller
1026 -- exits (to enable it to be awoken later). Otherwise it runs the next
1027 -- phase until all phases have been completed.
1028 --
1029 --
1030 --  Input Parameters
1031 --        p_migration_id        - of current migration
1032 --
1033 --
1034 --  Output Parameters
1035 --        errbuf  - buffer for output message (for CM manager)
1036 --
1037 --        retcode - program return code (for CM manager)
1038 --
1039 --
1040 -- ------------------------------------------------------------------------
1041 
1042 --
1043 PROCEDURE main_controller(errbuf OUT NOCOPY VARCHAR2,
1044                           retcode OUT NOCOPY NUMBER,
1045                           p_migration_id IN BINARY_INTEGER) IS
1046 --
1047 
1048 l_search_phase VARCHAR2(30);
1049 l_next_phase VARCHAR2(30);
1050 l_phase_name VARCHAR2(30);
1051 l_previous_phase VARCHAR2(30);
1052 l_previous VARCHAR2(30);
1053 e_fatal_error EXCEPTION;
1054 l_fatal_error_message VARCHAR2(200);
1055 r_migration_data hr_dm_utility.r_migration_rec;
1056 l_database_location VARCHAR2(30);
1057 l_request_data VARCHAR2(30);
1058 l_mig_status VARCHAR2(30);
1059 
1060 
1061 CURSOR csr_phase_rule IS
1062   SELECT phase_name, next_phase, database_location
1063     FROM hr_dm_phase_rules
1064     WHERE ((migration_type = r_migration_data.migration_type)
1065       AND (previous_phase = l_search_phase));
1066 
1067 CURSOR csr_paused_phase_rule IS
1068   SELECT previous_phase, next_phase
1069     FROM hr_dm_phase_rules
1070     WHERE ((migration_type = r_migration_data.migration_type)
1071       AND (phase_name = l_request_data));
1072 
1073 CURSOR csr_mig_status IS
1074   SELECT status
1075     FROM hr_dm_migrations
1076     WHERE migration_id = r_migration_data.migration_id;
1077 
1078 
1079 --
1080 BEGIN
1081 --
1082 
1083 -- initialize messaging
1084 hr_dm_utility.message_init;
1085 
1086 hr_dm_utility.message('ROUT','entry:hr_dm_master.main_controller', 5);
1087 hr_dm_utility.message('PARA','(p_migration_id - ' ||
1088                       p_migration_id || ')', 10);
1089 
1090 
1091 -- see if this is a migration run (l_request_data = NULL)
1092 -- OR
1093 -- is it a restart after slaves have finished? (l_request_data =
1094 --                                                    paused phase code)
1095 l_request_data := fnd_conc_global.request_data;
1096 hr_dm_utility.message('INFO','Request data - ' || l_request_data, 12);
1097 
1098 -- initialize main controller data
1099 controller_init(p_migration_id,
1100                 r_migration_data,
1101                 l_request_data);
1102 
1103 -- work out phases applicable to this migration
1104 --
1105 IF (l_request_data IS NULL) THEN
1106 -- seed first phase
1107   l_search_phase := 'START';
1108   l_next_phase := '?';
1109 ELSE
1110 -- seed with data for paused phase
1111   OPEN csr_paused_phase_rule;
1112   LOOP
1113     FETCH csr_paused_phase_rule INTO l_search_phase, l_next_phase;
1114     EXIT WHEN csr_paused_phase_rule%NOTFOUND;
1115   END LOOP;
1116   CLOSE csr_paused_phase_rule;
1117 END IF;
1118 
1119 -- seed previous phase name
1120 l_previous := 'START';
1121 
1122 WHILE (l_next_phase <> 'END') LOOP
1123   OPEN csr_phase_rule;
1124   FETCH csr_phase_rule INTO l_phase_name, l_next_phase,
1125                             l_database_location;
1126   EXIT WHEN csr_phase_rule%NOTFOUND;
1127 
1128 -- does it apply?
1129   IF (INSTR(l_database_location, r_migration_data.database_location) >0) THEN
1130 
1131   hr_dm_utility.message('INFO','Current phase is ' || l_phase_name, 11);
1132   hr_dm_utility.message('INFO','Request data - ' ||
1133                         NVL(l_request_data, '?'), 12);
1134 
1135 -- store the previous phase that applies
1136   l_previous_phase := l_previous;
1137   hr_dm_utility.message('INFO','Previous phase is ' || l_previous_phase, 11);
1138 
1139 
1140 
1141 -- is it completed or not awoken?
1142 -- if not, then run appropriate phase code
1143     IF ((hr_dm_utility.get_phase_status(l_phase_name, p_migration_id) <> 'C')
1144        OR (NVL(l_request_data, '?') <> '?')) THEN
1145 
1146 -- call generic master code
1147       IF (l_phase_name IN ('G', 'R', 'DA', 'DP', 'UA', 'UP', 'D', 'C')) THEN
1148         master(l_phase_name, l_previous_phase, r_migration_data);
1149       ELSE
1150 -- call non-generic master code
1151         IF (l_phase_name = 'I') THEN
1152 -- set current processing
1153           hr_dm_utility.set_process('Single threaded',
1154                                     l_phase_name,
1155                                     r_migration_data.migration_id);
1156           hr_dm_init.main(r_migration_data);
1157         ELSIF (l_phase_name = 'CP') THEN
1158 -- mark copy as started
1159 -- set current processing
1160           hr_dm_utility.set_process('Single threaded',
1161                                     l_phase_name,
1162                                     r_migration_data.migration_id);
1163           hr_dm_utility.update_phases(p_new_status => 'S',
1164                                       p_id => hr_dm_utility.get_phase_id('CP'
1165                                         , r_migration_data.migration_id));
1166 -- perform source copy on source database only
1167           IF (r_migration_data.database_location = 'S') THEN
1168             hr_dm_copy.source_copy(r_migration_data.migration_id,
1169                                    r_migration_data.last_migration_date);
1170           END IF;
1171 -- now let the user proceed with the manual copy,
1172 -- so mark the current migration as complete (on source database)
1173             hr_dm_utility.update_phases(p_new_status => 'C',
1174                                      p_id => hr_dm_utility.get_phase_id('CP'
1175                                           , r_migration_data.migration_id));
1176 -- and then the user must update the status to complete when manual copy
1177 -- process has been completed
1178         END IF;
1179 
1180       END IF;
1181 
1182 -- have we paused the main controller?
1183 -- if so, exit loop
1184       l_request_data := fnd_conc_global.request_data;
1185       EXIT WHEN NVL(l_request_data, '?') <> '?';
1186 
1187 -- did it complete? if not then update status and raise an error
1188       IF (hr_dm_utility.get_phase_status(l_phase_name, p_migration_id)
1189                                                                <> 'C') THEN
1190 -- update status of migration to error
1191         hr_dm_utility.update_migrations(p_new_status => 'E',
1192                                         p_id => p_migration_id);
1193         COMMIT;
1194 -- raise error
1195         l_fatal_error_message := 'Error in ' || l_phase_name || ' phase';
1196         report_error(l_phase_name, p_migration_id, l_fatal_error_message,
1197                      'M');
1198         RAISE e_fatal_error;
1199       END IF;
1200 
1201     END IF;
1202 
1203 -- store current applicable phase name for next iteration
1204     l_previous := l_phase_name;
1205   END IF;
1206   l_search_phase := l_phase_name;
1207   CLOSE csr_phase_rule;
1208 END LOOP;
1209 
1210 
1211 -- set up return values to concurrent manager
1212 retcode := 0;
1213 IF (NVL(l_request_data, '?') <> '?') THEN
1214   errbuf := 'No errors - examine logfiles for detailed reports.';
1215 ELSE
1216   errbuf := 'Master Controller is paused.';
1217 END IF;
1218 
1219 -- see the migration has errored
1220 -- if so, error this conc. program
1221 OPEN csr_mig_status;
1222 FETCH csr_mig_status INTO l_mig_status;
1223 CLOSE csr_mig_status;
1224 
1225 IF l_mig_status = 'E' THEN
1226   l_fatal_error_message := 'The migration is in error.';
1227   RAISE e_fatal_error;
1228 END IF;
1229 
1230 -- if we are doing a delete migration
1231 -- and the status is Complete
1232 -- then mark the migration as Finished
1233 
1234 IF r_migration_data.migration_type = 'D'
1235   AND l_mig_status = 'C' THEN
1236   UPDATE hr_dm_migrations
1237   SET status = 'F'
1238     WHERE migration_id = r_migration_data.migration_id;
1239   COMMIT;
1240 END IF;
1241 
1242 
1243 hr_dm_utility.message('INFO','Main controller', 15);
1244 hr_dm_utility.message('SUMM','Main controller', 20);
1245 hr_dm_utility.message('ROUT','exit:hr_dm_master.main_controller', 25);
1246 hr_dm_utility.message('PARA','(retcode - ' || retcode ||
1247                              ')(errbuf - ' || errbuf || ')', 30);
1248 
1249 
1250 -- error handling
1251 EXCEPTION
1252 WHEN e_fatal_error THEN
1253   retcode := 2;
1254   errbuf := 'An error occurred during the migration - examine logfiles' ||
1255             ' for detailed reports.';
1256   hr_dm_utility.error(SQLCODE,'hr_dm_range.main_controller',
1257                       l_fatal_error_message,'R');
1258   report_error(l_phase_name, p_migration_id,
1259                l_fatal_error_message || ' in hr_dm_master.main_controller',
1260                'M');
1261 WHEN OTHERS THEN
1262   retcode := 2;
1263   errbuf := 'An error occurred during the migration - examine logfiles' ||
1264             ' for detailed reports.';
1265   hr_dm_utility.error(SQLCODE,'hr_dm_master.main_controller','(none)','R');
1266   report_error(l_phase_name, p_migration_id,
1267                'Untrapped error in hr_dm_master.main_controller', 'M');
1268 
1269 --
1270 END main_controller;
1271 --
1272 
1273 
1274 
1275 end hr_dm_master;