DBA Data[Home] [Help]
Skip to content

PACKAGE BODY: APPS.WF_MAINTENANCE

Source


1 package body WF_MAINTENANCE as
2  /* $Header: wfmtn9b.pls 120.12.12010000.2 2008/08/26 20:42:20 alepe ship $ */
3 
4 g_CommitCounter NUMBER := 0;
5 g_docommit BOOLEAN := FALSE;
6 procedure PerformCommit;
7 
8 -- procedure PropagateChangedName
9 --   Locates all occurrences of an old username and changes to
10 --   the new username.
11 --
12 -- IN:
13 --   OldName - Old Username we are changing from.
14 --   NewName - New Username we are changing to.
15 --   CommitFrequency - Number of updates we perform before commit.
16 --
17 procedure PropagateChangedName(
18   OldName in varchar2,
19   NewName in varchar2,
20   docommit in BOOLEAN )
21 
22 is
23 
24 l_oldname VARCHAR2(320); -- Local Variable of OldName
25 l_newname VARCHAR2(320); -- Local Variable of NewName
26 
27 -- Setting up cursors for tables that would store a role name.
28 -- Some tables have columns named 'READ_ROLE' and 'WRITE_ROLE' that
29 -- are not currently used, so they are not included.
30 
31 cursor Items (l_oldname varchar2) is
32 select ITEM_TYPE, ITEM_KEY
33 from   WF_ITEMS
34 where  OWNER_ROLE = l_oldname;
35 
36 cursor ItemActivityStatuses (l_oldname varchar2) is
37 select ITEM_TYPE, ITEM_KEY, PROCESS_ACTIVITY
38 from   WF_ITEM_ACTIVITY_STATUSES
39 where  ASSIGNED_USER =  l_oldname;
40 
41 cursor ItemActivityStatuses_H (l_oldname varchar2) is
42 select ITEM_TYPE, ITEM_KEY, PROCESS_ACTIVITY
43 from   WF_ITEM_ACTIVITY_STATUSES_H
44 where  ASSIGNED_USER =  l_oldname;
45 
46 cursor Notifications (l_oldname varchar2) is
47 select NOTIFICATION_ID
48 from   WF_NOTIFICATIONS
49 where  RECIPIENT_ROLE     = l_oldname
50 or     ORIGINAL_RECIPIENT = l_oldname
51 or     more_info_role     = l_oldname
52 or     from_role          = l_oldname
53 or     responder          = l_oldname;
54 
55 cursor ProcessActivities (l_oldname varchar2) is
56 select PROCESS_ITEM_TYPE, PROCESS_NAME, PROCESS_VERSION,
57        INSTANCE_LABEL, INSTANCE_ID
58 from   WF_PROCESS_ACTIVITIES
59 where  PERFORM_ROLE = l_oldname;
60 
61 cursor RoutingRules (l_oldname varchar2) is
62 select RULE_ID
63 from   WF_ROUTING_RULES
64 where  ROLE = l_oldname
65 or     ACTION_ARGUMENT = l_oldname;
66 
67 cursor wfComments (l_oldname varchar2) is
68 select rowid
69 from   wf_comments
70 where  from_role = l_oldname
71 or     to_role = l_oldname
72 or     proxy_role = l_oldname;
73 
74 cursor roleAttributes (l_oldname varchar2) is
75 select wiav.rowid
76 from   wf_item_attribute_values wiav, wf_item_attributes wia
77 where  wia.type = 'ROLE'
78 and    wia.item_type = wiav.item_type
79 and    wia.name = wiav.name
80 and    wiav.text_value = l_oldname;
81 
82 l_roleInfoTAB WF_DIRECTORY.wf_local_roles_tbl_type;
83 
84 begin
85 l_newname := upper(substrb(NewName,1,320));
86 l_oldname := upper(substrb(OldName,1,320));
87 g_docommit := docommit;
88 
89 
90 /* We check to be sure that old name no longer exists (IE: the name was
91    changed).  If it is we can go ahead and effect the change.
92 
93    If the old name is still active and somewhere else in the directory services
94    we can't change it, so we have to raise the error that the name still
95    exists.
96 
97    We then check to be sure the new name is active and ready to receive
98    the records from the old name.
99 */
100 
101  WF_DIRECTORY.GetRoleInfo2(l_oldName, l_roleInfoTAB);
102 
103  if (l_roleInfoTAB(1).display_name is not NULL) then
104   if not (WF_DIRECTORY.ChangeLocalUsername(l_oldname, l_newname, FALSE)) then
105   WF_CORE.Token('ROLE', l_oldname);
106   WF_CORE.Token('PROCEDURE', 'PropagateChangedName');
107   WF_CORE.Token('PARAMETER', 'OldName');
108   WF_CORE.Raise('WFMTN_ACTIVEROLE');
109   return;
110   end if;
111  end if;
112 
113  WF_DIRECTORY.GetRoleInfo2(l_newname, l_roleInfoTAB);
114 
115  if  (l_roleInfoTAB(1).display_name is null) then
116   WF_CORE.Token('ROLE', l_newname);
117   WF_CORE.Raise('WFNTF_ROLE');
118   return;
119  end if;
120 
121 
122 /* We will now start looping through the cursors and updating OldName
123    to NewName
124 */
125 for I in Items (l_oldname) loop
126 
127  update WF_ITEMS
128  set    OWNER_ROLE = l_newname
129  where  ITEM_TYPE = i.item_type
130  and    item_key = i.item_key;
131 
132 PerformCommit();
133 end loop;
134 
135 for IAS in ItemActivityStatuses (l_oldname) loop
136 
137  update WF_ITEM_ACTIVITY_STATUSES
138  set    ASSIGNED_USER = l_newname
139  where  ITEM_TYPE = ias.item_type
140  and    ITEM_KEY = ias.item_key
141  and    PROCESS_ACTIVITY = ias.process_activity;
142 
143 PerformCommit();
144 end loop;
145 
146 for IASH in ItemActivityStatuses_H (l_oldname) loop
147 
148  update WF_ITEM_ACTIVITY_STATUSES_H
149  set    ASSIGNED_USER = l_newname
150  where  ITEM_TYPE = iash.item_type
151  and    ITEM_KEY = iash.item_key
152  and    PROCESS_ACTIVITY = iash.process_activity;
153 
154 PerformCommit();
155 end loop;
156 
157 for NTF in Notifications (l_oldname) loop
158 
159  update WF_NOTIFICATIONS
160  set    RECIPIENT_ROLE     = l_newname
161  where  NOTIFICATION_ID    = ntf.notification_id
162  and    RECIPIENT_ROLE     = l_oldname;
163 
164  update WF_NOTIFICATIONS
165  set    ORIGINAL_RECIPIENT = l_newname
166  where  NOTIFICATION_ID    = ntf.notification_id
167  and    ORIGINAL_RECIPIENT = l_oldname;
168 
169 update WF_NOTIFICATIONS
170  set    MORE_INFO_ROLE     = l_newname
171  where  NOTIFICATION_ID    = ntf.notification_id
172  and    MORE_INFO_ROLE     = l_oldname;
173 
174 update WF_NOTIFICATIONS
175  set    FROM_ROLE          = l_newname
176  where  NOTIFICATION_ID    = ntf.notification_id
177  and    FROM_ROLE          = l_oldname;
178 
179  update WF_NOTIFICATIONS
180  set    RESPONDER          = l_newname
181  where  NOTIFICATION_ID    = ntf.notification_id
182  and    RESPONDER          = l_oldname;
183 
184 PerformCommit();
185 end loop;
186 
187 for PAct in ProcessActivities (l_oldname) loop
188 
189  update WF_PROCESS_ACTIVITIES
190  set    PERFORM_ROLE = l_newname
191  where  PROCESS_ITEM_TYPE = pact.process_item_type
192  and    PROCESS_NAME = pact.process_name
193  and    PROCESS_VERSION = pact.process_version
194  and    INSTANCE_LABEL = pact.instance_label
195  and    INSTANCE_ID = pact.instance_id;
196 
197 PerformCommit();
198 end loop;
199 
200 for RR in RoutingRules (l_oldname) loop
201 
202  update WF_ROUTING_RULES
203  set    ROLE = l_newname
204  where  RULE_ID = rr.rule_id
205  and    ROLE = l_oldname;
206 
207  update WF_ROUTING_RULES
208  set    ACTION_ARGUMENT = l_newname
209  where  RULE_ID = rr.rule_id
210  and    ACTION_ARGUMENT = l_oldname;
211 
212 PerformCommit();
213 end loop;
214 
215 for wcom in wfComments (l_oldname) loop
216  update WF_COMMENTS
217  set    FROM_ROLE = l_newname,
218         FROM_USER = l_roleInfoTAB(1).display_name
219  where  rowid = wcom.rowid
220  and    FROM_ROLE = l_oldName;
221 
222  update WF_COMMENTS
223  set    TO_ROLE = l_newname,
224         TO_USER = l_roleInfoTAB(1).display_name
225  where  rowid = wcom.rowid
226  and    TO_ROLE = l_oldName;
227 
228  update WF_COMMENTS
229  set    PROXY_ROLE = l_newname
230  where  rowid = wcom.rowid
231  and    PROXY_ROLE = l_oldName;
232 
233  PerformCommit();
234 end loop;
235 
236 for rAttr in roleAttributes (l_oldname) loop
237   update WF_ITEM_ATTRIBUTE_VALUES
238   set    TEXT_VALUE = l_newname
239   where  rowid = rAttr.rowid;
240 
241   PerformCommit();
242 end loop;
243 commit;
244 
245 exception
246  when others then
247    WF_CORE.Context('WF_MAINTENANCE', 'PropagateChangedName', OldName, NewName);
248    raise;
249 end PropagateChangedName;
250 
251 -- procedure PerformCommit (private)
252 --   Decides if commit should occur and commits.
253 --
254 -- IN:
255 --   No Parameters.
256 --
257 procedure PerformCommit
258 
259 IS
260 BEGIN
261 if (g_docommit) then
262  g_commitCounter := g_commitCounter +1;
263  if (g_commitCounter >= WF_MAINTENANCE.g_CommitFrequency) then
264     commit;
265     g_commitCounter := 0;
266  end if;
267 end if;
268 
269 END PerformCommit;
270 
271 ------------------------------------------------------------------------------
272 /*
273 ** ValidateUserRoles - Validates and corrects denormalized user and role
274 **                     information in user/role relationships.
275 */
276 PROCEDURE ValidateUserRoles(p_BatchSize in NUMBER,
277                             p_check_dangling in BOOLEAN,
278                             p_check_missing_ura in BOOLEAN,
279                             p_UpdateWho in BOOLEAN,
280                             p_parallel_processes in number) is
281 
282   ColumnsMissing      EXCEPTION;
283   TooManyRows         EXCEPTION;
284 
285   pragma exception_init(ColumnsMissing, -904);
286   pragma exception_init(TooManyRows, -1422);
287 
288   TYPE charTab IS TABLE OF VARCHAR2(1) INDEX BY BINARY_INTEGER;
289   TYPE dateTab IS TABLE OF DATE 	  INDEX BY BINARY_INTEGER;
290   TYPE numTab  IS TABLE OF NUMBER	  INDEX BY BINARY_INTEGER;
291   TYPE idTab   IS TABLE OF ROWID 	  INDEX BY BINARY_INTEGER;
292   TYPE origTab IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
293   TYPE ownerTAGTAB  IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER;
294 
295   l_roleSrcTAB 	        WF_DIRECTORY.roleTable;
296   l_userSrcTAB 	        WF_DIRECTORY.userTable;
297   l_roleDestTAB 	WF_DIRECTORY.roleTable;
298   l_userDestTAB         WF_DIRECTORY.userTable;
299   l_rowIDTAB            idTab;
300   l_rowIDSrcTAB         idTab;
301   l_rowIDDestTAB        idTab;
302   l_stgIDTAB            idTab;
303   l_userStartSrcTAB     dateTab;
304   l_roleStartSrcTAB     dateTab;
305   l_userEndSrcTAB       dateTab;
306   l_roleEndSrcTAB       dateTab;
307   l_effStartSrcTAB      dateTab;
308   l_effEndSrcTAB        dateTab;
309   l_AssignTAB           charTab;
310   l_userStartDestTAB    dateTab;
311   l_roleStartDestTAB	dateTab;
312   l_userEndDestTAB      dateTab;
313   l_roleEndDestTAB 	dateTab;
314   l_effStartDestTAB     dateTab;
315   l_effEndDestTAB	dateTab;
316   l_relIDTAB	        numTab;
317   l_maxRows	        number;
318   l_userOrigIDSrcTAB    numTab;
319   l_roleOrigIDSrcTAB    numTab;
320   l_userOrigIDDestTAB   numTab;
321   l_roleOrigIDDEstTAB   numTab;
322   l_userOrigSrcTAB	origTab;
323   l_roleOrigSrcTAB      origTab;
324   l_userOrigDestTAB	origTab;
325   l_roleOrigDestTAB     origTab;
326   l_assigningRoleSrcTAB WF_DIRECTORY.roleTable;
327   l_asgStartSrcTAB	dateTab;
328   l_asgEndSrcTAB        dateTab;
329   l_startSrcTAB         dateTab;
330   l_endSrcTAB           dateTab;
331 
332   l_startDestTAB        dateTab;
333   l_endDestTAB          dateTab;
334   l_partTAB             numTab;
335   l_userID              number;
336   l_empID               number;
337 
338   sumTabIndex           number;
339   ur_index              number;
340   l_eIndex              number;
341 
342   l_activeAssigned      boolean;
343   l_updateDateTAB       dateTAB;
344   l_createDateTAB       dateTAB;
345   l_updatedByTAB        numTAB;
346   l_updateLoginTAB      numTAB;
347   l_createdByTAB        numTAB;
348   l_parentOrigTAB       origTAB;
349   l_parentOrigIDTAB     numTAB;
350   l_ownerTAGS           ownerTAGTAB;
351   -- <bug 6823723>
352   l_sql                 varchar2(6000);
353   l_defaultParProc      number;
354   l_parallelProc        varchar2(5);
355 
356   result number;
357   l_lockhandle varchar2(200);
358 
359   --Missing records in WF_USER_ROLE_ASSIGNMENTS
360   cursor c_missing_user_role_asg is
361     select user_name, role_name, -1, start_date, expiration_date,
362            created_by, creation_date, last_updated_by, last_update_date,
363            last_update_login, user_start_date, role_start_date,
364            user_end_date, role_end_date, partition_id,
365            effective_start_date, effective_end_date, user_orig_system,
366            user_orig_system_id, role_orig_system, role_orig_system_id,
367            parent_orig_system, parent_orig_system_id, owner_tag
368     from wf_local_user_roles wur
369     where not exists (select null
370                       from wf_user_role_assignments wura
371                       where wura.user_name = wur.user_name
372                       and wura.role_name = wur.role_name);
373 
374   --Invalid and Duplicated records in the (FND_USR) partition
375   cursor c_invalid_fnd_users is
376     select wu.rowid, wu.orig_system old_orig_system,
377            wu.orig_system_id old_orig_system_id,
378            decode(nvl(fu.employee_id, -1),-1,'FND_USR','PER') new_orig_system,
379            nvl(fu.employee_id, fu.user_id)
380     from   wf_local_roles partition (FND_USR) wu, fnd_user fu
381     where  wu.name = fu.user_name
382     and    (wu.orig_system <> decode(nvl(fu.employee_id, -1),-1,'FND_USR','PER')
383       or    wu.orig_system_id <> nvl(fu.employee_id, fu.user_id));
384 
385   -- Records with invalid or duplicate FND_USR/PER references
386   -- in WF_LOCAL_USER_ROLES
387   cursor c_invalOrigSys is
388    select wu.orig_system, wu.orig_system_id,
389           wur.role_orig_system, wur.role_orig_system_id,
390           wur.partition_id, wur.rowid
391    from   wf_local_user_roles wur,
392           wf_local_roles partition (FND_USR) wu
393    where  wu.name = wur.user_name
394    and    wur.user_orig_system in ('FND_USR','PER')
395    and    (wur.user_orig_system <> wu.orig_system
396     or     wur.user_orig_system_id <> wu.orig_system_id
397    --check for role_orig_system in case of self-reference
398     or (wur.partition_id=1 and  (wur.role_orig_system <> wu.orig_system
399     or     wur.role_orig_system_id <> wu.orig_system_id)));
400 
401   --We will correct the orig_system, orig_system_id information for any
402   --incorrect fnd_usr/per user/role records.  This is processed after the
403   --fnd_usr/per records in wf_local_roles are validated. The dates will be
404   --resolved in when c_userRoleAssignments are resolved.
405   cursor c_userSelfReference is
406     select wura.rowid, wur.rowid, wu.start_date, wu.expiration_date,
407            wu.orig_system, wu.orig_system_id
408     from   wf_local_user_roles partition (FND_USR) wur,
409            wf_local_roles partition (FND_USR) wu,
410            wf_user_role_assignments partition (FND_USR)  wura
411     --Equi-joins to select the proper relationships between the tables
412     where  wura.partition_id = wu.partition_id
413     and    wura.partition_id = wu.partition_id
414     and    wur.user_name = wu.name
415     and    wur.role_name = wu.name
416     and    wura.assigning_role = wu.name
417     and    wura.user_name = wu.name
418     and    wura.role_name = wu.name
419     --Criteria to select records that need to be corrected, beginning with
420     --broad checks (if effective dates are null, no reason to check further)
421     --and working down to more specific checks between the orig_system/id
422     and    ((wur.effective_start_date is null or
423              wur.effective_end_date is null or
424              wura.effective_start_date is null or
425              wura.effective_end_date is null)
426       or    ((wur.user_orig_system <> wu.orig_system) or
427              (wur.user_orig_system_id <> wu.orig_system_id) or
428              (wur.role_orig_system <> wu.orig_system) or
429              (wur.role_orig_system_id <> wu.orig_system_id))
430       or    (wura.user_orig_system is null or wura.role_orig_system is null or
431              wura.user_orig_system_id is null or
432              wura.user_orig_system_id is null)
433       or    (wura.user_orig_system <> wu.orig_system)
434       or    (wura.user_orig_system_id <> wu.orig_system_id)
435       or    (wura.role_orig_system <> wu.orig_system)
436       or    (wura.role_orig_system_id <> wu.orig_system_id)
437       or    (wu.start_date is null and
438               (wur.start_date is not null or
439                wur.user_start_date is not null or
440                wur.role_start_date is not null or
441                wur.effective_start_date <> to_date(1,'J')))
442       or    (wu.start_date is not null and
443               (wur.start_date is null or wur.user_start_date is null or
444                wur.role_start_date is null or wur.start_date <> wu.start_date or
445                wur.user_start_date <> wu.start_date or
446                wur.role_start_date <> wu.start_date or
447                wur.effective_start_date <> wu.start_date))
448       or    (wu.expiration_date is null and
449               (wur.expiration_date is not null or
450                wur.user_end_date is not null or wur.role_end_date is not null or
451                wur.effective_end_date <> to_date('9999/01/01','YYYY/MM/DD')))
452       or    (wu.expiration_date is not null and
453               (wur.expiration_date is null or wur.user_end_date is null or
454                wur.role_end_date is null or
455                wur.expiration_date <> wu.expiration_date or
456                wur.user_end_date <> wu.expiration_date or
457                wur.role_end_date <> wu.expiration_date or
458                wur.effective_end_date <> wu.expiration_date)));
459 
460   --Now we will correct other user/role relationships, including the user
461   --orig_system/id information of any record that an fnd_usr/per may be
462   --participating in.
463   cursor c_UserRoleAssignments is
464       select rowid, wura_id,wur_id,role_name,user_name,
465       assigning_role, start_date, end_Date,role_start_date,
466       role_end_date, user_start_date,user_end_date,
467       role_orig_system,role_orig_system_id,
468       user_orig_system, user_orig_system_id,
469       assigning_role_start_date, assigning_role_end_date,
470       effective_start_date, effective_end_date,
471       relationship_id
472       from wf_ur_validate_stg
473       order by  ROLE_NAME, USER_NAME;
474 
475   CURSOR dangling_UR_refs is
476     select rowid
477     from   wf_local_user_roles
478     where  user_name not in (select name from wf_local_roles)
479     or     role_name not in (select name from wf_local_roles);
480 
481   CURSOR dangling_URA_refs is
482     select rowid
483     from   wf_user_role_assignments
484     where  user_name not in (select name from wf_local_roles)
485     or     role_name not in (select name from wf_local_roles);
486 
487   l_modulePkg varchar2(240) := 'WF_MAINTENANCE.ValidateUserRoles';
488 
489 begin
490 -- Log only
491 -- BINDVAR_SCAN_IGNORE[2]
492   WF_LOG_PKG.String(WF_LOG_PKG.LEVEL_PROCEDURE, l_modulePkg,
493                      'Begin ValidateUserRoles('||p_batchSize||')');
494   --First validate the inbound parameter(s)
495   if (p_BatchSize is NULL or (p_BatchSize < 1)) then
496     l_MaxRows := 10000;
497   else
498     l_MaxRows := p_BatchSize;
499   end if;
500 
501   -- Acquire a session lock to ensure that only one instance of the program is
502   -- running at a time.
503   dbms_lock.allocate_unique('WF_MAINTENANCE.ValidateUserRoles',l_lockhandle);
504 
505   if (dbms_lock.request(lockhandle=>l_lockhandle,
506                         lockmode=>dbms_lock.x_mode,
507                         timeout=>0) <> 0) then
508    wf_core.raise('WF_LOCK_FAIL');
509   end if;
510 
511   if (p_check_dangling is not null and p_check_dangling) then
512   --Validate that the users and roles who participate in user/role
513   --relationships actually exist.
514   begin
515     <<Dangling_UR_Reference>>
516     loop
517       open dangling_UR_refs;
518         fetch dangling_UR_refs bulk collect into l_rowIDTAB limit l_maxRows;
519       close dangling_UR_refs;
520 
521       if (l_rowIDTAB.COUNT > 0) then
522         forall i in l_rowIDTAB.FIRST..l_rowIDTAB.LAST
523           DELETE from WF_LOCAL_USER_ROLES
524           WHERE  rowid = l_rowIDTAB(i);
525           commit;
526       end if;
527 
528       if (l_rowIDTAB.COUNT < l_maxRows) then
529         exit Dangling_UR_Reference;
530       end if;
531     end loop Dangling_UR_Reference;
532   exception
533     when others then
534       if dangling_UR_refs%ISOPEN then
535         close dangling_UR_refs;
536       end if;
537       raise;
538   end;
539   --Truncate the rowid tab.
540   l_rowIDTAB.DELETE;
541   begin
542     <<Dangling_URA_Reference>>
543     loop
544       open dangling_URA_refs;
545         fetch dangling_URA_refs bulk collect into l_rowIDTAB limit l_maxRows;
546       close dangling_URA_refs;
547 
548       if (l_rowIDTAB.COUNT > 0) then
549         forall i in l_rowIDTAB.FIRST..l_rowIDTAB.LAST
550           DELETE from WF_USER_ROLE_ASSIGNMENTS
551           WHERE  rowid = l_rowIDTAB(i);
552           commit;
553       end if;
554 
555       if (l_rowIDTAB.COUNT < l_maxRows) then
556         exit Dangling_URA_Reference;
557       end if;
558     end loop Dangling_URA_Reference;
559   exception
560     when others then
561       if dangling_URA_refs%ISOPEN then
562         close dangling_URA_refs;
563       end if;
564       raise;
565   end;
566   --Truncate the rowid tab.
567   l_rowIDTAB.DELETE;
568  end if;
569 
570    if (p_check_missing_ura is not null and p_check_missing_ura) then
571     --Validate that the users and roles who participate in user/role
572     --relationships actually exist.
573     begin
574       <<Missing_URA_Reference>>
575       loop
576         l_userSrcTAB.DELETE;
577         open c_missing_user_role_asg;
578           fetch c_missing_user_role_asg bulk collect into l_userSrcTAB,
579             l_roleSrcTAB, l_relIDTAB, l_startSrcTAB, l_endSrcTAB,
580             l_createdByTAB, l_createDateTAB, l_updatedByTAB, l_updateDateTAB,
581             l_updateLoginTAB, l_userStartSrcTAB, l_roleStartSrcTAB,
582             l_userEndSrcTAB, l_roleEndSrcTAB, l_partTAB, l_effStartSrcTAB,
583             l_effEndSrcTAB, l_userOrigSrcTAB, l_userOrigIDSrcTAB,
584             l_roleOrigSrcTAB, l_roleOrigIDSrcTAB, l_parentOrigTAB,
585             l_parentOrigIDTAB, l_ownerTAGS
586             limit l_maxRows;
587         close c_missing_user_role_asg;
588 
589         if (l_userSrcTAB.COUNT > 0) then
590           begin
591             forall i in l_userSrcTAB.FIRST..l_userSrcTAB.LAST save exceptions
592               insert into WF_USER_ROLE_ASSIGNMENTS (USER_NAME,
593                 ROLE_NAME, RELATIONSHIP_ID, ASSIGNING_ROLE, START_DATE,
594                 END_DATE, CREATED_BY, CREATION_DATE, LAST_UPDATED_BY,
595                 LAST_UPDATE_DATE, LAST_UPDATE_LOGIN, USER_START_DATE,
596                 ROLE_START_DATE, ASSIGNING_ROLE_START_DATE, USER_END_DATE,
597                 ROLE_END_DATE, ASSIGNING_ROLE_END_DATE, PARTITION_ID,
598                 EFFECTIVE_START_DATE, EFFECTIVE_END_DATE, USER_ORIG_SYSTEM,
599                 USER_ORIG_SYSTEM_ID, ROLE_ORIG_SYSTEM, ROLE_ORIG_SYSTEM_ID,
600                 PARENT_ORIG_SYSTEM, PARENT_ORIG_SYSTEM_ID, OWNER_TAG)
601                 values (l_userSrcTAB(i), l_roleSrcTAB(i), l_relIDTAB(i),
602                  l_roleSrcTAB(i), l_startSrcTAB(i), l_endSrcTAB(i),
603                  l_createdByTAB(i), l_createDateTAB(i), l_updatedByTAB(i),
604                  l_updateDateTAB(i), l_updateLoginTAB(i), l_userStartSrcTAB(i),
605                  l_roleStartSrcTAB(i), l_roleStartSrcTAB(i), l_userEndSrcTAB(i),
606                  l_roleEndSrcTAB(i), l_roleEndSrcTAB(i), l_partTAB(i),
607                  l_effStartSrcTAB(i), l_effEndSrcTAB(i), l_userOrigSrcTAB(i),
608                  l_userOrigIDSrcTAB(i), l_roleOrigSrcTAB(i),
609                  l_roleOrigIDSrcTAB(i), l_parentOrigTAB(i),
610                  l_parentOrigIDTAB(i), l_ownerTAGS(i));
611               commit;
612           exception
613             when others then
614               for j in 1..sql%bulk_exceptions.count loop
615                 if (sql%bulk_exceptions(j).ERROR_CODE = 1) then
616                   --Ignore a dup_val_on_index.  That just means that the
617                   --user/role name combination was already assigned during this
618                   --job.
619                   null;
620                 else
621                   raise;
622                 end if;
623               end loop;
624           end;
625         end if;
626 
627         if (l_userSrcTAB.COUNT < l_maxRows) then
628           exit Missing_URA_Reference;
629         end if;
630       end loop Missing_URA_Referencee;
631     exception
632       when others then
633         if c_missing_user_role_asg%ISOPEN then
634           close c_missing_user_role_asg;
635         end if;
636         raise;
637     end;
638   end if;
639 
640   --Now we will correct any invalid fnd_usr records in WF_LOCAL_ROLES.  This
641   --orig_system can have errors because we routinely have to change the
642   --orig_system, orig_system_id whenever a user is associated or dis-associated
643   --with an employee.
644   begin
645     <<fnd_usr_loop>>
646     loop
647       --Clear the l_rowIDTAB before the next iteration
648       l_rowIDTAB.DELETE;
649       open  c_invalid_fnd_users;
650       fetch c_invalid_fnd_users bulk collect into l_rowIDTAB, l_userOrigSrcTAB,
651         l_userOrigIDSrcTAB, l_userOrigDestTAB, l_userOrigIDDestTAB
652           limit l_maxRows;
653       close c_invalid_fnd_users;
654 
655       if (l_rowIDTAB.count > 0) then
656         begin
657           forall i in l_rowIDTAB.FIRST..l_rowIDTAB.LAST save exceptions
658             UPDATE WF_LOCAL_ROLES
659             SET    orig_system = l_userOrigDestTAB(i),
660                    orig_system_id = l_userOrigIDDestTAB(i)
661             WHERE  rowid = l_rowIDTAB(i);
662         exception
663           when others then
664             for j in 1..sql%bulk_exceptions.count loop
665               l_eIndex := sql%bulk_exceptions(j).ERROR_INDEX;
666               delete from wf_local_roles
667               where  rowid = l_rowIDTAB(l_eIndex);
668             end loop;
669         end;
670         commit;
671       end if;
672       if (l_rowIDTab.count < l_maxRows) then
673         commit;
674         exit fnd_usr_loop;
675       end if;
676     end loop fnd_usr_loop;
677   exception
678     when others then
679       if c_invalid_fnd_users%ISOPEN then
680         close c_invalid_fnd_users;
681       end if;
682       raise;
683   end; --End of duplicate/invalid FND_USR/PER user correction.
684 
685   -- Now we correct the FND_USR/PER orig_system values on the user side
686   -- of user/role assignments as well as user-self-references in
687   -- WF_LOCAL_USER_ROLES
688 
689   begin
690   <<inval_orig_sys_loop>>
691     loop
692       --Clear the l_rowIDTAB before the next iteration
693       l_rowIDTAB.DELETE;
694       open  c_invalOrigSys;
695       fetch c_invalOrigSys bulk collect into l_userOrigSrcTAB,
696         l_userOrigIDSrcTAB, l_roleOrigSrcTAB, l_roleOrigIDSrcTAB,
697         l_partTAB,l_rowIDTAB
698         limit l_maxRows;
699       close c_invalOrigSys;
700 
701       if (l_rowIDTAB.count > 0) then
702           for i in  l_rowIDTAB.FIRST..l_rowIDTAB.LAST loop
703             -- check whether this is a case of user=role
704            if l_partTAB(i) = 1 then
705               -- set the role_orig_system values as well.
706               l_roleOrigSrcTAB(i) := l_userOrigSrcTAB(i);
707               l_roleOrigIDSrcTAB(i) := l_userOrigIDSrcTAB(i);
708            end if;
709           end loop;
710           --perform the bulk update.. delete duplicates in case of
711           -- dup_val_on_index Exception.
712           begin
713           forall i in l_rowIDTAB.FIRST..l_rowIDTAB.LAST save exceptions
714             UPDATE WF_LOCAL_USER_ROLES
715             SET    user_orig_system = l_userOrigSrcTAB(i),
716                    user_orig_system_id = l_userOrigIDSrcTAB(i),
717                    role_orig_system = l_roleOrigSrcTAB(i),
718                    role_orig_system_id = l_roleOrigIDSrcTAB(i)
719             WHERE  rowid = l_rowIDTAB(i);
720            exception
721             when others then
722              for j in 1..sql%bulk_exceptions.count loop
723               if (sql%bulk_exceptions(j).ERROR_CODE = 1) then
724                l_eIndex := sql%bulk_exceptions(j).ERROR_INDEX;
725                delete from wf_local_user_roles
726                where  rowid = l_rowIDTAB(l_eIndex);
727               end if;
728              end loop;
729            end;
730            commit;
731       end if;
732       if (l_rowIDTab.count < l_maxRows) then
733         commit;
734         exit inval_orig_sys_loop;
735       end if;
736     end loop inval_orig_sys_loop;
737   exception
738     when others then
739       if c_invalOrigSys%ISOPEN then
740         close c_invalOrigSys;
741       end if;
742       raise;
743   end; --End of duplicate/invalid FND_USR/PER correction in WF_LOCAL_USER_ROLES.
744 
745   --Next, we correct the corrupt self-reference records in
746   --wf_user_role_Assignments and wf_local_user_Roles.
747   begin
748   <<self_refer_loop>>
749   loop
750     --We will commit on each loop cycle to prevent fetch across commits, we will
751     --close and reopen the cursor on each fetch.  This would mean that we are
752     --pulling more than 10000 if we loop more than once and would rather have
753     --a performance impact here than encounter rollback segment problems.
754     --The where criteria of the cursor will not re-select the updated rows so
755     --we do not have to worry about retaining a position.
756     open c_userSelfReference;
757     fetch c_userSelfReference
758     bulk collect into l_rowIDTAB, l_rowIDSrcTAB, l_startSrcTAB,
759                       l_endSrcTAB, l_userOrigSrcTAB, l_userOrigIDSrcTAB
760     limit l_maxRows;
761     close c_userSelfReference;
762 
763     --We now have pl/sql tables in memory that we can update with the new
764     --values. So we loop through them and begin the processing.
765     if (l_rowIDTAB.COUNT < 1) then
766       exit self_refer_loop;
767     end if;
768 
769     --We now have a complete series of pl/sql tables with
770     --all of the start/end dates and calculated effective start/end dates
771     --We can then issue the bulk  update.
772     begin
773      if (p_UpdateWho is not null and p_UpdateWho) then
774       forall tabIndex in l_rowIDTAB.FIRST..l_rowIDTAB.LAST save exceptions
775         update  WF_USER_ROLE_ASSIGNMENTS
776         set     ROLE_START_DATE = l_StartSrcTAB(tabIndex),
777                 ROLE_END_DATE = l_EndSrcTAB(tabIndex),
778                 USER_START_DATE = l_StartSrcTAB(tabIndex),
779                 USER_END_DATE = l_EndSrcTAB(tabIndex),
780                 START_DATE    = l_StartSrcTAB(tabIndex),
781                 END_DATE      = l_EndSrcTAB(tabIndex),
782                 EFFECTIVE_START_DATE = nvl(l_StartSrcTAB(tabIndex),
783                                            to_date(1,'J')),
784                 EFFECTIVE_END_DATE = nvl(l_EndSrcTAB(tabIndex),
785                                          to_date('9999/01/01', 'YYYY/MM/DD')),
786                 ASSIGNING_ROLE_START_DATE = l_StartSrcTAB(tabIndex),
787                 ASSIGNING_ROLE_END_DATE = l_EndSrcTAB(tabIndex),
788                 USER_ORIG_SYSTEM=l_userOrigSrcTAB(tabIndex),
789                 ROLE_ORIG_SYSTEM=l_userOrigSrcTAB(tabIndex),
790                 USER_ORIG_SYSTEM_ID=l_userOrigIDSrcTAB(tabIndex),
791                 ROLE_ORIG_SYSTEM_ID=l_userOrigIDSrcTAB(tabIndex),
792                 LAST_UPDATED_BY = FND_GLOBAL.USER_ID,
793                 LAST_UPDATE_DATE = SYSDATE,
794                 LAST_UPDATE_LOGIN  = FND_GLOBAL.LOGIN_ID
795         where   rowid = l_rowIDTAB(tabIndex);
796      else --donot touch the WHO columns. This is default behavior
797       forall tabIndex in l_rowIDTAB.FIRST..l_rowIDTAB.LAST save exceptions
798         update  WF_USER_ROLE_ASSIGNMENTS
799         set     ROLE_START_DATE = l_StartSrcTAB(tabIndex),
800                 ROLE_END_DATE = l_EndSrcTAB(tabIndex),
801                 USER_START_DATE = l_StartSrcTAB(tabIndex),
802                 USER_END_DATE = l_EndSrcTAB(tabIndex),
803                 START_DATE    = l_StartSrcTAB(tabIndex),
804                 END_DATE      = l_EndSrcTAB(tabIndex),
805                 EFFECTIVE_START_DATE = nvl(l_StartSrcTAB(tabIndex),
806                                            to_date(1,'J')),
807                 EFFECTIVE_END_DATE = nvl(l_EndSrcTAB(tabIndex),
808                                          to_date('9999/01/01', 'YYYY/MM/DD')),
809                 ASSIGNING_ROLE_START_DATE = l_StartSrcTAB(tabIndex),
810                 ASSIGNING_ROLE_END_DATE = l_EndSrcTAB(tabIndex),
811                 USER_ORIG_SYSTEM=l_userOrigSrcTAB(tabIndex),
812                 ROLE_ORIG_SYSTEM=l_userOrigSrcTAB(tabIndex),
813                 USER_ORIG_SYSTEM_ID=l_userOrigIDSrcTAB(tabIndex),
814                 ROLE_ORIG_SYSTEM_ID=l_userOrigIDSrcTAB(tabIndex)
815         where   rowid = l_rowIDTAB(tabIndex);
816      end if;
817     exception
818        when others then
819          for j in 1..sql%bulk_exceptions.count loop
820            if (sql%bulk_exceptions(j).ERROR_CODE = 1) then
821              --If update violates dup_val_on_index, we can simply delete.
822              l_eIndex := sql%bulk_exceptions(j).ERROR_INDEX;
823              delete from wf_user_role_assignments
824              where rowid = l_rowIDTAB(l_eIndex);
825            else
826              raise;
827            end if;
828          end loop;
829      end;
830 
831      --Commit work to save rollback
832      commit;
833 
834      -- update WF_LOCAL_USER_ROLES
835      begin
836       if (p_UpdateWho is not null and p_UpdateWho) then
837        forall tabIndex in l_rowIDSrcTAB.FIRST..l_rowIDSrcTAB.LAST save exceptions
838         update wf_local_user_roles partition (FND_USR)
839         set     ROLE_START_DATE = l_StartSrcTAB(tabIndex),
840                 ROLE_END_DATE = l_EndSrcTAB(tabIndex),
841                 USER_START_DATE = l_StartSrcTAB(tabIndex),
842                 USER_END_DATE = l_EndSrcTAB(tabIndex),
843                 START_DATE    = l_StartSrcTAB(tabIndex),
844                 EXPIRATION_DATE  = l_EndSrcTAB(tabIndex),
845                 EFFECTIVE_START_DATE = nvl(l_StartSrcTAB(tabIndex),
846                                            to_date(1,'J')),
847                 EFFECTIVE_END_DATE = nvl(l_EndSrcTAB(tabIndex),
848                                          to_date('9999/01/01', 'YYYY/MM/DD')),
849                 LAST_UPDATED_BY = FND_GLOBAL.USER_ID,
850                 LAST_UPDATE_DATE = SYSDATE,
851                 LAST_UPDATE_LOGIN  = FND_GLOBAL.LOGIN_ID
852          where  rowid = l_rowIDSrcTAB(tabIndex);
853       else  --donot touch the WHO columns. This is default behavior
854        forall tabIndex in l_rowIDSrcTAB.FIRST..l_rowIDSrcTAB.LAST save exceptions
855         update wf_local_user_roles partition (FND_USR)
856         set     ROLE_START_DATE = l_StartSrcTAB(tabIndex),
857                 ROLE_END_DATE = l_EndSrcTAB(tabIndex),
858                 USER_START_DATE = l_StartSrcTAB(tabIndex),
859                 USER_END_DATE = l_EndSrcTAB(tabIndex),
860                 START_DATE    = l_StartSrcTAB(tabIndex),
861                 EXPIRATION_DATE  = l_EndSrcTAB(tabIndex),
862                 EFFECTIVE_START_DATE = nvl(l_StartSrcTAB(tabIndex),
863                                            to_date(1,'J')),
864                 EFFECTIVE_END_DATE = nvl(l_EndSrcTAB(tabIndex),
865                                          to_date('9999/01/01', 'YYYY/MM/DD'))
866          where  rowid = l_rowIDSrcTAB(tabIndex);
867        end if;
868       end;
869 
870     if (l_rowIDTAB.COUNT < l_maxRows) then --Last batch, no need to refetch
871       commit;
872       exit self_refer_loop;
873     else
874       -- reset the ROWID Table before the next set of fetch
875       l_rowIDTAB.DELETE;
876       commit;
877     end if;
878   end loop self_refer_loop;
879   exception
880    when others then
881      if (c_userSelfReference%isOpen) then
882        close c_userSelfReference;
883      end if;
884      raise;
885   end; --end of self-reference fix
886 
887   commit;--commit the self reference records
888 
889   -- reset the PL/SQL tables before we fetch the user-role cursor
890   l_rowIDTAB.delete;
891   l_rowIDSrcTAB.delete;
892   l_startSrcTAB.delete;
893   l_endSrcTAB.delete;
894   l_userOrigSrcTAB.delete;
895   l_userOrigIDSrcTAB.delete;
896 
897   --Initialize the sumTabIndex counter.
898   sumTabIndex := 0;
899 
900   --Enable parallel DML
901   execute IMMEDIATE 'alter session enable parallel dml';
902 
903   --truncate the stage table now
904   WF_DDL.TruncateTable('WF_UR_VALIDATE_STG',WF_CORE.Translate('WF_SCHEMA'),
905                        FALSE);
906 
907   -- <bug 6823723>
908   select min(to_number(value))
909   into   l_defaultParProc
910   from   v$parameter
911   where  name in ('parallel_max_servers','cpu_count');
912 
913   if ((p_parallel_processes is NULL) or (p_parallel_processes < 1) or
914       (mod(p_parallel_processes, 1) <> 0) or (p_parallel_processes > l_defaultParProc)
915       ) then
916     l_parallelProc := to_char(l_defaultParProc) ;
917   else
918     l_parallelProc := to_char(p_parallel_processes);
919   end if;
920   -- </bug 6823723>
921 
922   -- populate the stage table
923   -- bug 6823723. Now inserting as a dynamic DML to include the number of parallel processes
924   l_sql :=
925   'INSERT /*+ append parallel(WF_UR_VALIDATE_STG,'|| l_parallelProc ||') */
926   INTO WF_UR_VALIDATE_STG (WURA_ID, WUR_ID , ROLE_NAME , USER_NAME ,
927   ASSIGNING_ROLE , START_DATE , END_DATE , ROLE_START_DATE, ROLE_END_DATE
928   , USER_START_DATE , USER_END_DATE , ROLE_ORIG_SYSTEM ,
929   ROLE_ORIG_SYSTEM_ID , USER_ORIG_SYSTEM , USER_ORIG_SYSTEM_ID ,
930   ASSIGNING_ROLE_START_DATE , ASSIGNING_ROLE_END_DATE ,
931   EFFECTIVE_START_DATE , EFFECTIVE_END_DATE , RELATIONSHIP_ID )
932   SELECT /*+ ordered parallel(WURA,'|| l_parallelProc ||') parallel(WR,'|| l_parallelProc ||
933           ') parallel (wu,'|| l_parallelProc ||')
934              parallel (WAR,'|| l_parallelProc ||') parallel(WUR,'|| l_parallelProc ||') */
935          WURA.ROWID, WUR.ROWID, WURA.ROLE_NAME, WURA.USER_NAME,
936          WURA.ASSIGNING_ROLE,
937          DECODE(WURA.USER_NAME, WURA.ROLE_NAME, WU.START_DATE,
938                 WURA.START_DATE) START_DATE,
939          DECODE(WURA.USER_NAME, WURA.ROLE_NAME, WU.EXPIRATION_DATE,
940                 WURA.END_DATE) END_DATE,
941          WR.START_DATE, WR.EXPIRATION_DATE, WU.START_DATE,
942          WU.EXPIRATION_DATE, WR.ORIG_SYSTEM, WR.ORIG_SYSTEM_ID,
943          WU.ORIG_SYSTEM, WU.ORIG_SYSTEM_ID, WAR.START_DATE,
944          WAR.EXPIRATION_DATE,
945          GREATEST(NVL(WURA.START_DATE, TO_DATE(1,''J'')),
946                   NVL(WURA.USER_START_DATE, TO_DATE(1,''J'')),
947                   NVL(WURA.ROLE_START_DATE, TO_DATE(1,''J'')),
948                   NVL(WURA.ASSIGNING_ROLE_START_DATE,
949                       TO_DATE(1,''J''))) EFFECTIVE_START_DATE,
950          LEAST(NVL(WURA.END_DATE, TO_DATE(''9999/01/01'', ''YYYY/MM/DD'')),
951                NVL(WURA.USER_END_DATE, TO_DATE(''9999/01/01'', ''YYYY/MM/DD'')),
952                NVL(WURA.ROLE_END_DATE, TO_DATE(''9999/01/01'', ''YYYY/MM/DD'')),
953                NVL(WURA.ASSIGNING_ROLE_END_DATE,
954                    TO_DATE(''9999/01/01'', ''YYYY/MM/DD''))) EFFECTIVE_END_DATE,
955          WURA.RELATIONSHIP_ID
956     FROM
957          WF_USER_ROLE_ASSIGNMENTS WURA,
958          WF_LOCAL_USER_ROLES WUR ,
959          WF_LOCAL_ROLES WAR,
960          WF_LOCAL_ROLES WU,
961          WF_LOCAL_ROLES WR
962    WHERE WURA.PARTITION_ID = WAR.PARTITION_ID
963      AND WURA.ASSIGNING_ROLE=WAR.NAME
964      AND WURA.USER_NAME= WUR.USER_NAME
965      AND WURA.ROLE_NAME=WUR.ROLE_NAME
966      AND WUR.USER_NAME = WU.NAME
967      AND WUR.USER_ORIG_SYSTEM=WU.ORIG_SYSTEM
968      AND WUR.USER_ORIG_SYSTEM_ID= WU.ORIG_SYSTEM_ID
969      AND WUR.ROLE_NAME = WR.NAME
970      AND WUR.ROLE_ORIG_SYSTEM= WR.ORIG_SYSTEM
971      AND WUR.ROLE_ORIG_SYSTEM_ID= WR.ORIG_SYSTEM_ID
972      AND WUR.PARTITION_ID = WR.PARTITION_ID
973      AND WUR.PARTITION_ID <> 1
974      AND WAR.PARTITION_ID <> 1
975      AND ( ( WUR.EFFECTIVE_START_DATE IS NULL or
976              WUR.EFFECTIVE_END_DATE IS NULL or
977              WURA.EFFECTIVE_START_DATE IS NULL or
978              WURA.EFFECTIVE_END_DATE IS NULL )
979       OR ( WURA.EFFECTIVE_START_DATE <> GREATEST(NVL(WURA.START_DATE,
980          TO_DATE(1,''J'')), NVL(WURA.USER_START_DATE, TO_DATE(1,''J'')), NVL(
981          WURA.ROLE_START_DATE, TO_DATE(1,''J'')), NVL(
982          WURA.ASSIGNING_ROLE_START_DATE, TO_DATE(1,''J''))) )
983       OR ( WURA.EFFECTIVE_END_DATE <> LEAST(NVL(WURA.END_DATE, TO_DATE(
984          ''9999/01/01'', ''YYYY/MM/DD'')), NVL(WURA.USER_END_DATE, TO_DATE(
985          ''9999/01/01'', ''YYYY/MM/DD'')) , NVL(WURA.ROLE_END_DATE, TO_DATE(
986          ''9999/01/01'', ''YYYY/MM/DD'')), NVL(WURA.ASSIGNING_ROLE_END_DATE,
987          TO_DATE(''9999/01/01'', ''YYYY/MM/DD''))))
988       OR (WURA.USER_NAME = WURA.ROLE_NAME and
989           (nvl(wura.start_date, to_date(1,''J'')) <>
990            nvl(wu.start_date, to_date(1,''J'')) or
991            nvl(wura.end_date, to_date(''9999/01/01'', ''YYYY/MM/DD'')) <>
992            nvl(wu.expiration_date, to_date(''9999/01/01'', ''YYYY/MM/DD''))))
993       OR ( ( WUR.ASSIGNMENT_TYPE IS NULL )
994       OR WUR.ASSIGNMENT_TYPE NOT IN (''D'', ''I'', ''B'') )
995       OR ( WURA.USER_ORIG_SYSTEM IS NULL
996       OR WURA.ROLE_ORIG_SYSTEM IS NULL
997       OR WURA.USER_ORIG_SYSTEM_ID IS NULL
998       OR WURA.ROLE_ORIG_SYSTEM_ID IS NULL )
999       OR ( WURA.USER_ORIG_SYSTEM <> WU.ORIG_SYSTEM
1000       OR WURA.USER_ORIG_SYSTEM_ID <> WU.ORIG_SYSTEM_ID
1001       OR WURA.ROLE_ORIG_SYSTEM <> WR.ORIG_SYSTEM
1002       OR WURA.ROLE_ORIG_SYSTEM_ID <> WR.ORIG_SYSTEM_ID )
1003       OR ( ( WU.START_DATE IS NULL
1004      AND ( WUR.USER_START_DATE IS NOT NULL
1005       OR WURA.USER_START_DATE IS NOT NULL ) )
1006       OR ( WU.START_DATE IS NOT NULL
1007      AND ( WUR.USER_START_DATE IS NULL
1008       OR WUR.USER_START_DATE <> WU.START_DATE
1009       OR WURA.USER_START_DATE IS NULL
1010       OR WURA.USER_START_DATE <> WU.START_DATE ) )
1011       OR ( WU.EXPIRATION_DATE IS NULL
1012      AND ( WUR.USER_END_DATE IS NOT NULL
1013       OR WURA.USER_END_DATE IS NOT NULL ) )
1014       OR ( WU.EXPIRATION_DATE IS NOT NULL
1015      AND ( WUR.USER_END_DATE IS NULL
1016       OR WUR.USER_END_DATE <> WU.EXPIRATION_DATE
1017       OR WURA.USER_END_DATE IS NULL
1018       OR WURA.USER_END_DATE <> WU.EXPIRATION_DATE ) ) )
1019       OR ( ( WR.START_DATE IS NULL
1020      AND ( WUR.ROLE_START_DATE IS NOT NULL
1021       OR WURA.ROLE_START_DATE IS NOT NULL ) )
1022       OR ( WR.START_DATE IS NOT NULL
1023      AND ( WUR.ROLE_START_DATE IS NULL
1024       OR WUR.ROLE_START_DATE <> WR.START_DATE
1025       OR WURA.ROLE_START_DATE IS NULL
1026       OR WURA.ROLE_START_DATE <> WR.START_DATE ) )
1027       OR ( WR.EXPIRATION_DATE IS NULL
1028      AND ( WUR.ROLE_END_DATE IS NOT NULL
1029       OR WURA.ROLE_END_DATE IS NOT NULL ) )
1030       OR ( WR.EXPIRATION_DATE IS NOT NULL
1031      AND ( WUR.ROLE_END_DATE IS NULL
1032       OR WUR.ROLE_END_DATE <> WR.EXPIRATION_DATE
1033       OR WURA.ROLE_END_DATE IS NULL
1034       OR WURA.ROLE_END_DATE <> WR.EXPIRATION_DATE ) ) )
1035       OR ( ( WAR.START_DATE IS NULL
1036      AND WURA.ASSIGNING_ROLE_START_DATE IS NOT NULL )
1037       OR ( WAR.START_DATE IS NOT NULL
1038      AND ( WURA.ASSIGNING_ROLE_START_DATE IS NULL
1039       OR WURA.ASSIGNING_ROLE_START_DATE <> WAR.START_DATE ) )
1040       OR ( WAR.EXPIRATION_DATE IS NULL
1041      AND WURA.ASSIGNING_ROLE_END_DATE IS NOT NULL )
1042       OR ( WAR.EXPIRATION_DATE IS NOT NULL
1043      AND ( WURA.ASSIGNING_ROLE_END_DATE IS NULL
1044       OR WURA.ASSIGNING_ROLE_END_DATE <> WAR.EXPIRATION_DATE ) ) ) )' ;
1045 
1046     execute IMMEDIATE l_sql;
1047     commit;
1048     execute IMMEDIATE 'alter session disable parallel dml';
1049 
1050    open c_UserRoleAssignments;
1051   <<outer_loop>>
1052   loop
1053     fetch c_UserRoleAssignments
1054     bulk collect into l_stgIDTAB, l_rowIDTAB, l_rowIDSrcTAB, l_roleSrcTAB,
1055                       l_userSrcTAB, l_assigningRoleSrcTAB, l_startSrcTAB,
1056                       l_endSrcTAB, l_roleStartSrcTAB, l_roleEndSrcTAB,
1057                       l_userStartSrcTAB, l_userEndSrcTAB, l_roleOrigSrcTAB,
1058                       l_roleOrigIDSrcTAB,l_userOrigSrcTAB,
1059                       l_userOrigIDSrcTAB,l_asgStartSrcTAB,
1060                       l_asgEndSrcTAB, l_effStartSrcTAB,l_effEndSrcTAB,
1061                       l_relIDTAB
1062     limit l_maxRows;
1063 
1064     --We now have pl/sql tables in memory that we can update with the new
1065     --values. So we loop through them and begin the processing.
1066     if (l_rowIDTAB.COUNT < 1) then
1067       exit outer_loop;
1068     end if;
1069 
1070     --We now have a complete series of pl/sql tables with
1071     --all of the start/end dates and calculated effective start/end dates
1072     --We can then issue the bulk  update..
1073     if (p_UpdateWho is not null and p_UpdateWho) then
1074      forall tabIndex in l_rowIDTAB.FIRST..l_rowIDTAB.LAST
1075       update  WF_USER_ROLE_ASSIGNMENTS
1076       set     ROLE_START_DATE = l_roleStartSrcTAB(tabIndex),
1077               ROLE_END_DATE = l_roleEndSrcTAB(tabIndex),
1078               USER_START_DATE = l_userStartSrcTAB(tabIndex),
1079               USER_END_DATE = l_userEndSrcTAB(tabIndex),
1080               START_DATE = l_startSrcTAB(tabIndex),
1081               END_DATE = l_endSRcTAB(tabIndex),
1082               EFFECTIVE_START_DATE = l_effStartSrcTAB(tabIndex),
1083               EFFECTIVE_END_DATE = l_effEndSrcTAB(tabIndex),
1084               ASSIGNING_ROLE_START_DATE = l_asgStartSrcTAB(tabIndex),
1085               ASSIGNING_ROLE_END_DATE = l_asgEndSrcTAB(tabIndex),
1086               USER_ORIG_SYSTEM=l_userOrigSrcTAB(tabIndex),
1087               ROLE_ORIG_SYSTEM=l_roleOrigSrcTAB(tabIndex),
1088               USER_ORIG_SYSTEM_ID=l_userOrigIDSrcTAB(tabIndex),
1089               ROLE_ORIG_SYSTEM_ID=l_roleOrigIDSrcTAB(tabIndex),
1090               LAST_UPDATED_BY = FND_GLOBAL.USER_ID,
1091               LAST_UPDATE_DATE = SYSDATE,
1092               LAST_UPDATE_LOGIN  = FND_GLOBAL.LOGIN_ID
1093       where   rowid = l_rowIDTAB(tabIndex);
1094    else --Donot touch WHO columns. This is default behavior
1095     forall tabIndex in l_rowIDTAB.FIRST..l_rowIDTAB.LAST
1096       update  WF_USER_ROLE_ASSIGNMENTS
1097       set     ROLE_START_DATE = l_roleStartSrcTAB(tabIndex),
1098               ROLE_END_DATE = l_roleEndSrcTAB(tabIndex),
1099               USER_START_DATE = l_userStartSrcTAB(tabIndex),
1100               USER_END_DATE = l_userEndSrcTAB(tabIndex),
1101               START_DATE = l_startSrcTAB(tabIndex),
1102               END_DATE = l_endSRcTAB(tabIndex),
1103               EFFECTIVE_START_DATE = l_effStartSrcTAB(tabIndex),
1104               EFFECTIVE_END_DATE = l_effEndSrcTAB(tabIndex),
1105               ASSIGNING_ROLE_START_DATE = l_asgStartSrcTAB(tabIndex),
1106               ASSIGNING_ROLE_END_DATE = l_asgEndSrcTAB(tabIndex),
1107               USER_ORIG_SYSTEM=l_userOrigSrcTAB(tabIndex),
1108               ROLE_ORIG_SYSTEM=l_roleOrigSrcTAB(tabIndex),
1109               USER_ORIG_SYSTEM_ID=l_userOrigIDSrcTAB(tabIndex),
1110               ROLE_ORIG_SYSTEM_ID=l_roleOrigIDSrcTAB(tabIndex)
1111       where   rowid = l_rowIDTAB(tabIndex);
1112    end if;
1113 
1114     --We will reloop through the assignment pl/sql tables and populate the
1115     --summary pl/sql tables.
1116     <<summarize_assignments>>
1117     for tabIndex in l_rowIDTAB.FIRST..l_rowIDTAB.LAST loop
1118     --we need to insert into summary table if this is the first
1119     --record to be inserted or, we have a new user/role combination
1120     --in the assignment table, which hasnt yet been inserted into the
1121     --summary table
1122       if ((l_roleDestTab.COUNT < 1) or
1123           (l_rowIDSrcTAB(tabIndex) <> l_rowIDDestTAB(sumTabIndex))) then
1124         -- before inserting, check whether the summarytable has
1125         -- grown too large
1126         if sumTabIndex >= l_maxRows then
1127           --limit reached for summary table, so perform
1128           --the bulk update and clear off the table.
1129           --We need to perform the bulk update here in addition to
1130           --bulk update after exit from the loop, so that clearing
1131           --the summary table will not lose user/role effective date
1132           --information when duplicate user/role
1133           --combinations are spread across multiple groups
1134          if (p_UpdateWho is not null and p_UpdateWho) then
1135            forall destTabIndex in l_roleDestTab.FIRST..l_roleDestTab.LAST
1136             UPDATE WF_LOCAL_USER_ROLES wur
1137             SET    ROLE_START_DATE = l_roleStartDestTAB(destTabIndex),
1138                    ROLE_END_DATE   = l_roleEndDestTAB(destTabIndex),
1139                    USER_START_DATE = l_userStartDestTAB(destTabIndex),
1140                    USER_END_DATE = l_userEndDestTAB(destTabIndex),
1141                    START_DATE = l_startDestTAB(destTabIndex),
1142                    EXPIRATION_DATE = l_endDestTAB(destTabIndex),
1143                    EFFECTIVE_START_DATE = l_effStartDestTAB(destTabIndex),
1144                    EFFECTIVE_END_DATE = l_effEndDestTAB(destTabIndex),
1145                    ASSIGNMENT_TYPE = l_assignTAB(destTabIndex),
1146                    LAST_UPDATED_BY = FND_GLOBAL.USER_ID,
1147                    LAST_UPDATE_LOGIN = FND_GLOBAL.Login_Id,
1148                    LAST_UPDATE_DATE  = SYSDATE
1149              WHERE rowid = l_rowIDDestTAB(destTabIndex);
1150           else --Do not touch WHO columns. This is default behavior
1151            forall destTabIndex in l_roleDestTab.FIRST..l_roleDestTab.LAST
1152             UPDATE WF_LOCAL_USER_ROLES wur
1153             SET    ROLE_START_DATE = l_roleStartDestTAB(destTabIndex),
1154                    ROLE_END_DATE   = l_roleEndDestTAB(destTabIndex),
1155                    USER_START_DATE = l_userStartDestTAB(destTabIndex),
1156                    USER_END_DATE = l_userEndDestTAB(destTabIndex),
1157                    START_DATE = l_startDestTAB(destTabIndex),
1158                    EXPIRATION_DATE = l_endDestTAB(destTabIndex),
1159                    EFFECTIVE_START_DATE = l_effStartDestTAB(destTabIndex),
1160                    EFFECTIVE_END_DATE = l_effEndDestTAB(destTabIndex),
1161                    ASSIGNMENT_TYPE = l_assignTAB(destTabIndex)
1162              WHERE rowid = l_rowIDDestTAB(destTabIndex);
1163           end if;
1164           l_roleStartDestTAB.DELETE;
1165           l_roleEndDestTAB.DELETE;
1166           l_userStartDestTAB.DELETE;
1167           l_userEndDestTAB.DELETE;
1168           l_effStartDestTAB.DELETE;
1169           l_effEndDestTAB.DELETE;
1170           l_assignTAB.DELETE;
1171           l_startDestTAB.DELETE;
1172           l_endDestTAB.DELETE;
1173           l_roleDestTAB.DELETE;
1174           l_userDestTAB.DELETE;
1175           l_userOrigDestTAB.DELETE;
1176           l_userOrigIDDestTAB.DELETE;
1177           l_roleOrigDestTAB.DELETE;
1178           l_roleOrigIDDestTAB.DELETE;
1179           l_rowIDDestTAB.DELETE;
1180 
1181           sumTabIndex := 0;
1182         end if;	--sumTabIndex >= l_maxRows
1183 
1184         --now perform the insert
1185         sumTabIndex := sumTabIndex + 1;
1186         l_RoleDestTAB(sumTabIndex)       := l_roleSrcTAB(tabIndex);
1187         l_UserDestTAB(sumTabIndex)       := l_userSRcTAB(tabIndex);
1188         l_userOrigDestTAB(sumTabIndex)   := l_userOrigSrcTAB(tabIndex);
1189         l_userOrigIDDestTAB(sumTabIndex) := l_userOrigIDSrcTAB(tabIndex);
1190         l_roleOrigDestTAB(sumTabIndex)   := l_roleOrigSrcTAB(tabIndex);
1191         l_roleOrigIDDestTAB(sumTabIndex) := l_roleOrigIDSrcTAB(tabIndex);
1192         l_roleStartDestTAB(sumTabIndex)  := l_roleStartSrcTAB(tabIndex);
1193         l_roleEndDestTAB(sumTabIndex)    := l_roleEndSrcTAB(tabIndex);
1194         l_userStartDestTAB(sumTabIndex)  := l_userStartSrcTAB(tabIndex);
1195         l_userEndDestTAB(sumTabIndex)    := l_userEndSrcTAB(tabIndex);
1196         l_effStartDestTAB(sumTabIndex)   := l_effStartSrcTAB(tabIndex);
1197         l_effEndDestTAB(sumTabIndex)     := l_effEndSrcTAB(tabIndex);
1198         l_rowIDDestTAB(sumTabIndex)      := l_rowIDSrcTAB(TabIndex);
1199 
1200         --Check to see if the assignment is active.
1201         if (l_effEndSrcTAB(tabIndex) > trunc(SYSDATE) and
1202             l_effStartSrcTab(tabIndex) <= trunc(SYSDATE)) then
1203           l_activeAssigned := TRUE;
1204         else
1205           l_activeAssigned := FALSE;
1206         end if;
1207 
1208         --Determine the initial assignment_type.
1209         if  l_relIDTAB(tabIndex) = -1 then
1210           l_AssignTAB(sumTabIndex):='D';
1211           l_startDestTAB(sumTabIndex)    :=l_startSrcTAB(tabIndex);
1212           l_endDestTAB(sumTabIndex)      :=l_endSrcTAB(tabIndex);
1213         else
1214           l_AssignTAB(sumTabIndex):='I';
1215           l_startDestTAB(sumTabIndex)    :=null;
1216           l_endDestTAB(sumTabIndex)      :=null;
1217         end if;
1218       else  --Record is already in the summary table so update effective dates
1219       if l_effStartSrcTAB(tabIndex) < l_effStartDestTAB(sumTabIndex) then
1220         l_effStartDestTAB(sumTabIndex) := l_effStartSrcTAB(tabIndex);
1221       end if;
1222 
1223       if l_effEndSrcTAB(tabIndex) > l_effEndDestTAB(sumTabIndex) then
1224         l_effEndDestTAB(sumTabIndex) := l_effEndSrcTAB(tabIndex);
1225       end if;
1226 
1227       -- if this is a direct assignment then we need to set the start
1228       -- and end dates
1229       if l_relIDTAB(tabIndex) = -1 then
1230          l_startDestTAB(sumTabIndex)    :=l_startSrcTAB(tabIndex);
1231          l_endDestTAB(sumTabIndex)      :=l_endSrcTAB(tabIndex);
1232       end if;
1233 
1234       --if the assignment type in summary table is Direct and
1235       --we encountered an inherited assignment in the Assignment table
1236       --or if the assignment type in summary table is inherited and we
1237       --encountered a direct assignment in the Assignment table
1238       --update the assignment_Type to Both
1239 
1240       if (l_effEndSrcTAB(tabIndex) > trunc(SYSDATE) and
1241           l_effStartSrcTAB(tabIndex) <= trunc(SYSDATE)) then
1242         --This is an active assignment so we need to determine if an
1243         --active assignment was already used in calculating assignment_type
1244         if (l_activeAssigned) then
1245           --An active assignment was already used in the calculation so this
1246           --assignment will be used to determine if and existing 'D' or 'I'
1247           --should be changed into a 'B'
1248           if (((l_AssignTAB(sumTabIndex) = 'D') and
1249                (l_relIDTAB(tabIndex) <> -1)) or
1250                ((l_AssignTAB(sumTabIndex) = 'I') and
1251                (l_relIDTAB(tabIndex) = -1))) then
1252 
1253             l_AssignTAB(sumTabIndex) := 'B';
1254           end if;
1255         else
1256           --This is the first active assignment, so set the initial value
1257           --Determine the initial assignment_type.
1258           if  l_relIDTAB(tabIndex) = -1 then
1259             l_AssignTAB(sumTabIndex):='D';
1260             l_startDestTAB(sumTabIndex)    :=l_startSrcTAB(tabIndex);
1261             l_endDestTAB(sumTabIndex)      :=l_endSrcTAB(tabIndex);
1262           else
1263             l_AssignTAB(sumTabIndex):='I';
1264             l_startDestTAB(sumTabIndex)    :=null;
1265             l_endDestTAB(sumTabIndex)      :=null;
1266           end if;
1267 
1268           --Now set l_activeAssigned to TRUE.
1269           l_activeAssigned := TRUE;
1270         end if;
1271       else
1272         --This is an expired assignment, so we will set the assignment_type
1273         --only if we have not already initialized/modified with an
1274         --active assignment.
1275         if NOT (l_activeAssigned) then
1276           if  l_relIDTAB(tabIndex) = -1 then
1277             l_AssignTAB(sumTabIndex):='D';
1278             l_startDestTAB(sumTabIndex)    :=l_startSrcTAB(tabIndex);
1279             l_endDestTAB(sumTabIndex)      :=l_endSrcTAB(tabIndex);
1280           else
1281             l_AssignTAB(sumTabIndex):='I';
1282             l_startDestTAB(sumTabIndex)    :=null;
1283             l_endDestTAB(sumTabIndex)      :=null;
1284           end if;
1285         end if;
1286       end if;
1287     end if;
1288   end loop summarize_assignments;
1289 
1290     --Check to see if we have the last batch and do not need to re-fetch
1291     if (l_rowIDTAB.COUNT < l_maxRows) then
1292       commit;
1293       exit outer_loop;
1294     else
1295       -- reset the ROWID Table before the next set of fetch
1296       l_rowIDTAB.DELETE;
1297       commit;
1298     end if;
1299   end loop outer_loop;
1300 
1301   --when we reach here, we need to bulk update the leftover records,
1302   --if any, in the summary table.
1303 
1304   if (l_roleDestTAB.COUNT) > 0 then
1305    if (p_UpdateWho is not null and p_UpdateWho) then
1306     forall destTabIndex in l_roleDestTab.FIRST..l_roleDestTab.LAST
1307       UPDATE WF_LOCAL_USER_ROLES wur
1308       SET    ROLE_START_DATE = l_roleStartDestTAB(destTabIndex),
1309              ROLE_END_DATE   = l_roleEndDestTAB(destTabIndex),
1310              USER_START_DATE = l_userStartDestTAB(destTabIndex),
1311              USER_END_DATE = l_userEndDestTAB(destTabIndex),
1312              EFFECTIVE_START_DATE = l_effStartDestTAB(destTabIndex),
1313              EFFECTIVE_END_DATE = l_effEndDestTAB(destTabIndex),
1314              START_DATE = l_startDestTAB(destTabIndex),
1315              EXPIRATION_DATE = l_endDestTAB(destTabIndex),
1316              ASSIGNMENT_TYPE = l_assignTAB(destTabIndex),
1317              LAST_UPDATED_BY = FND_GLOBAL.USER_ID,
1318              LAST_UPDATE_LOGIN = FND_GLOBAL.Login_Id,
1319              LAST_UPDATE_DATE  = SYSDATE
1320        WHERE rowid = l_rowIDDestTAB(destTabIndex);
1321    else --Do not touch WHO columns. This is default behavior.
1322     forall destTabIndex in l_roleDestTab.FIRST..l_roleDestTab.LAST
1323       UPDATE WF_LOCAL_USER_ROLES wur
1324       SET    ROLE_START_DATE = l_roleStartDestTAB(destTabIndex),
1325              ROLE_END_DATE   = l_roleEndDestTAB(destTabIndex),
1326              USER_START_DATE = l_userStartDestTAB(destTabIndex),
1327              USER_END_DATE = l_userEndDestTAB(destTabIndex),
1328              EFFECTIVE_START_DATE = l_effStartDestTAB(destTabIndex),
1329              EFFECTIVE_END_DATE = l_effEndDestTAB(destTabIndex),
1330              START_DATE = l_startDestTAB(destTabIndex),
1331              EXPIRATION_DATE = l_endDestTAB(destTabIndex),
1332              ASSIGNMENT_TYPE = l_assignTAB(destTabIndex)
1333        WHERE rowid = l_rowIDDestTAB(destTabIndex);
1334    end if;
1335   end if;
1336   commit; --Commit final work.
1337   --close the cursor now
1338    if (c_userRoleAssignments%ISOPEN) then
1339       close c_userRoleAssignments;
1340    end if;
1341   --release lock
1342   if (dbms_lock.release(l_lockhandle) <> 0) then
1343    wf_core.raise('WF_LOCK_FAIL');
1344   end if;
1345 
1346 exception
1347   when others then
1348     result := dbms_lock.release(l_lockhandle);
1349     if (c_userRoleAssignments%ISOPEN) then
1350       close c_userRoleAssignments;
1351     end if;
1352     raise;
1353 end;
1354 
1355 end WF_MAINTENANCE;