DBA Data[Home] [Help]

PACKAGE BODY: APPS.WF_PURGE

Source


1 package body WF_PURGE as
2 /* $Header: wfprgb.pls 120.13.12010000.2 2008/09/08 11:39:36 ajverma ship $ */
3 
4 --Private Variables
5 l_docommit boolean;
6 l_runtimeonly boolean;
7 
8 -- procedure Move_To_History
9 --   Move wf_item_activity_status rows for particular itemtype/key from
10 --   main table to history table.
11 -- IN:
12 --   itemtype - Item type to move, or null for all itemtypes
13 --   itemkey - Item key to move, or null for all itemkeys
14 --
15 procedure Move_To_History(
16   itemtype in varchar2,
17   itemkey in varchar2)
18 is
19 begin
20   Null;
21 end Move_To_History;
22 
23 --
24 -- procedure Item_Activity_Statuses
25 --   Delete from wf_item_activity_statuses and wf_item_activity_statuses_h
26 --   where end_date before argument.
27 -- IN:
28 --   itemtype - Item type to delete, or null for all itemtypes
29 --   itemkey - Item key to delete, or null for all itemkeys
30 --   enddate - Date to obsolete to
31 --
32 procedure Item_Activity_Statuses(
33   itemtype in varchar2,
34   itemkey in varchar2,
35   enddate in date)
36 is
37 begin
38    Null;
39 end Item_Activity_Statuses;
40 
41 --
42 -- procedure Items
43 --   Delete items with end_time before argument.
44 -- IN:
45 --   itemtype - Item type to delete, or null for all itemtypes
46 --   itemkey - Item key to delete, or null for all itemkeys
47 --   enddate - Date to obsolete to
48 --   docommit- Do not commit if set to false
49 --
50 procedure Items(
51   itemtype in varchar2,
52   itemkey in varchar2,
53   enddate in date,
54   docommit in boolean,
55   force in boolean,
56   purgesigs in pls_integer)
57 is
58   dummy     varchar2(240);
59   keep  number;                      -- Bug 1895332
60   TYPE nidListTAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
61   l_nidListTAB nidListTAB;
62   l_tempListTAB nidListTAB;
63   l_keycount number;
64   l_signature boolean := TRUE;
65   xenddate date;
66   l_ecx_sql  varchar2(2000);
67 
68  -- CTILLEY bug 2755885 include rowid in where clause to resolve
69  -- infinite loop
70 
71  -- CTILLEY bug 3228475 - remove like item type and item key to
72  -- performance violation.  Added item5purge to query records
73  -- where itemtype is passed but no itemkey.  No longer supporting
74  -- partial values for either item type or item key.
75 
76    cursor item2purge is
77      select WI.END_DATE, WI.ITEM_TYPE, WI.ITEM_KEY
78      from   WF_ITEMS WI
79      where  WI.ITEM_TYPE = itemtype
80      and    WI.END_DATE <= enddate
81      and    WI.END_DATE > xenddate
82       and exists
83          (select null
84           from WF_ITEM_TYPES WIT
85           where WI.END_DATE+nvl(WIT.PERSISTENCE_DAYS,0)<=enddate
86           and WI.ITEM_TYPE = WIT.NAME
87           and WIT.PERSISTENCE_TYPE = Wf_Purge.persistence_type)
88       and not exists
89          (select null
90           from WF_ITEMS WI2
91           WHERE WI2.END_DATE IS NULL
92           START WITH WI2.ITEM_TYPE = WI.ITEM_TYPE
93           AND WI2.ITEM_KEY = WI.ITEM_KEY
94           CONNECT BY PRIOR WI2.ITEM_TYPE = WI2.PARENT_ITEM_TYPE
95           AND PRIOR WI2.ITEM_KEY = WI2.PARENT_ITEM_KEY
96           UNION ALL
97           select null
98           from WF_ITEMS WI2
99           WHERE WI2.END_DATE IS NULL
100           START WITH WI2.ITEM_TYPE = WI.ITEM_TYPE
101           AND WI2.ITEM_KEY = WI.ITEM_KEY
102           CONNECT BY PRIOR WI2.PARENT_ITEM_TYPE = WI2.ITEM_TYPE
103           AND PRIOR WI2.PARENT_ITEM_KEY = WI2.ITEM_KEY)
104 	order by WI.END_DATE;
105 
106    -- JWSMITH bug 2070056 - add new cursor for performance
107    cursor item3purge is
108      select WI.END_DATE, WI.ITEM_TYPE, WI.ITEM_KEY
109      from   WF_ITEMS WI
110      where  WI.ITEM_TYPE = itemtype
111       and   WI.ITEM_KEY = itemkey
112       and   WI.end_date <= enddate
113        and exists
114           (select null
115            from WF_ITEM_TYPES WIT
116            where WI.END_DATE+nvl(WIT.PERSISTENCE_DAYS,0)<=enddate
117            and WI.ITEM_TYPE = WIT.NAME
118            and WIT.PERSISTENCE_TYPE = Wf_Purge.persistence_type)
119        and not exists
120           (select null
121            from WF_ITEMS WI2
122            WHERE WI2.END_DATE IS NULL
123            START WITH WI2.ITEM_TYPE = WI.ITEM_TYPE
124            AND WI2.ITEM_KEY = WI.ITEM_KEY
125            CONNECT BY PRIOR WI2.ITEM_TYPE = WI2.PARENT_ITEM_TYPE
126            AND PRIOR WI2.ITEM_KEY = WI2.PARENT_ITEM_KEY
127            UNION ALL
128            select null
129            from WF_ITEMS WI2
130            WHERE WI2.END_DATE IS NULL
131            START WITH WI2.ITEM_TYPE = WI.ITEM_TYPE
132            AND WI2.ITEM_KEY = WI.ITEM_KEY
133            CONNECT BY PRIOR WI2.PARENT_ITEM_TYPE = WI2.ITEM_TYPE
134            AND PRIOR WI2.PARENT_ITEM_KEY = WI2.ITEM_KEY);
135 
136     -- CTILLEY bug 2642057 - added new cursor for use when FORCE
137     -- arg is TRUE.
138     cursor item4purge is
139       select WI.END_DATE, WI.ITEM_TYPE, WI.ITEM_KEY
140       from  WF_ITEMS WI
141       where WI.ITEM_KEY = itemkey
142       and   WI.ITEM_TYPE = itemtype
143       and   WI.end_date <= enddate;
144 
145     -- CTILLEY bug 3228475 - Added new cursor to resolve performance violation
146     -- of using like condition.  We will no longer support passing partial values
147     -- for item type or item key.
148 
149    cursor item5purge is
150      select /*+ first_rows index(WI,WF_ITEMS_N3) */
151             WI.END_DATE, WI.ITEM_TYPE, WI.ITEM_KEY
152      from   WF_ITEMS WI
153      where  WI.END_DATE <= enddate
154      and    WI.END_DATE > xenddate
155       and exists
156          (select null
157           from WF_ITEM_TYPES WIT
158           where WI.END_DATE+nvl(WIT.PERSISTENCE_DAYS,0)<=enddate
159           and WI.ITEM_TYPE = WIT.NAME
160           and WIT.PERSISTENCE_TYPE = Wf_Purge.persistence_type)
161       and not exists
162          (select null
163           from WF_ITEMS WI2
164           WHERE WI2.END_DATE IS NULL
165           START WITH WI2.ITEM_TYPE = WI.ITEM_TYPE
166           AND WI2.ITEM_KEY = WI.ITEM_KEY
167           CONNECT BY PRIOR WI2.ITEM_TYPE = WI2.PARENT_ITEM_TYPE
168           AND PRIOR WI2.ITEM_KEY = WI2.PARENT_ITEM_KEY
169           UNION ALL
170           select null
171           from WF_ITEMS WI2
172           WHERE WI2.END_DATE IS NULL
173           START WITH WI2.ITEM_TYPE = WI.ITEM_TYPE
174           AND WI2.ITEM_KEY = WI.ITEM_KEY
175           CONNECT BY PRIOR WI2.PARENT_ITEM_TYPE = WI2.ITEM_TYPE
176           AND PRIOR WI2.PARENT_ITEM_KEY = WI2.ITEM_KEY);
177 
178   no_lock exception;
179   pragma EXCEPTION_INIT(no_lock, -54);
180 
181   -- ora-2292 = integrity constraint (%s.%s) violated - child record found
182   in_other_status_table exception;
183   pragma EXCEPTION_INIT(in_other_status_table, -02292);
184 
185   -- CTILLEY 2755885
186   -- ora-1436 CONNECT BY loop in user data - parent_item_type = item_type
187   connect_by_loop exception;
188   pragma EXCEPTION_INIT(connect_by_loop,-1436);
189 
190   -- <rwunderl:3751558>
191   invalid_component exception;
192   pragma EXCEPTION_INIT(invalid_component, -302);
193 
194   invalid_identifier exception;
195   pragma EXCEPTION_INIT(invalid_identifier, -201);
196   -- </rwunderl:3751558>
197 begin
198 
199   xenddate := to_date(1, 'J');
200   -- Disallow future date in enddate
201   -- Avoid something being purged before its defined persistence period.
202   if (enddate > sysdate) then
203     Wf_Core.Token('SYSDATE', to_char(sysdate));
204     Wf_Core.Raise('WF_FUTURE_END_DATE');
205   end if;
206 
207   if ((itemkey is not null and (instr(itemkey,'%')>0 or itemtype is null))
208       or (instr(itemtype,'%')>0)) then
209         wf_core.raise('WFSQL_ARGS');
210   end if;
211 
212   -- Build ECX Purge sql
213   --<rwunderl:3751558>
214   l_ecx_sql := 'begin ECX_PURGE.Purge_Items(:1, :2, :3, ';
215   if (l_docommit) then
216     l_ecx_sql := l_ecx_sql||'TRUE';
217   else
218     l_ecx_sql := l_ecx_sql||'FALSE';
219   end if;
220 
221   if (nvl(l_runtimeonly, TRUE)) then
222     l_ecx_sql := l_ecx_sql||', TRUE';
223   else
224     l_ecx_sql := l_ecx_sql||', FALSE';
225   end if;
226 
227   l_ecx_sql := l_ecx_sql||'); end;';
228   --</rwunderl:3751558>
229 
230   -- for all items that are valid to purge
231   -- outer loop for purging items.
232 
233   <<outer_purge>>
234   loop
235 
236     if (force) then   -- CTILLEY bug 2642057
237       open item4purge;
238     -- JWSMITH bug 2070056
239     -- CTILLEY bug 3228475 - no longer supporting partial values for itemtype
240     -- and itemkey.
241     elsif (itemtype is not null and itemkey is null) then
242         open item2purge;
243     elsif (itemtype is not null) then
244         open item3purge;
245     else
246         open item5purge;
247     end if;
248 
249     <<item_purge_loop>>
250     loop
251 
252        -- CTILLEY bug 2642057
253        if (force) then
254           -- Bug 4163328
255           -- Use bulk operations to improve performance
256           FETCH item4purge BULK COLLECT INTO l_enddateTAB,
257                                              l_itemtypeTAB,
258                                              l_itemkeyTAB LIMIT wf_purge.commit_frequency;
259       	  exit outer_purge when l_itemkeyTAB.COUNT = 0;
260 
261        -- JWSMITH bug 2070056
262        elsif (itemtype is not null and itemkey is null) then
263           FETCH item2purge BULK COLLECT INTO l_enddateTAB,
264                                              l_itemtypeTAB,
265                                              l_itemkeyTAB LIMIT wf_purge.commit_frequency;
266           exit outer_purge when l_itemkeyTAB.COUNT = 0;
267 
268        -- CTILLEY bug 3228475
269        elsif (itemtype is not null) then
270           FETCH item3purge BULK COLLECT INTO l_enddateTAB,
271                                              l_itemtypeTAB,
272                                              l_itemkeyTAB LIMIT wf_purge.commit_frequency;
273           exit outer_purge when l_itemkeyTAB.COUNT = 0;
274 
275        else
276           FETCH item5purge BULK COLLECT INTO l_enddateTAB,
277                                              l_itemtypeTAB,
278                                              l_itemkeyTAB LIMIT wf_purge.commit_frequency;
279           exit outer_purge when l_itemkeyTAB.COUNT = 0;
280        end if;
281 
282     l_keycount := l_itemkeyTAB.COUNT;
283 
284     -- set row lock on item
285     <<outer_lock_loop>>
286     FOR j IN l_itemkeyTAB.FIRST..l_itemkeyTAB.LAST loop
287 
288       if (j > l_itemkeyTAB.LAST) then
289         exit;
290       end if;
291 
292       -- If we cannot lock current item, try to lock the last item on the index table.
293       -- If we cannot acquire lock on the last item, delete last item and get the
294       -- next last item on the index table until we can acquire a lock.
295       if ( not (wf_item.acquire_lock(l_itemtypeTAB(j), l_itemkeyTAB(j), FALSE))) then
296         xenddate := l_enddateTAB(j);
297         <<lock_loop>>
298 	loop
299 	  if (l_itemkeyTAB.COUNT < j ) then
300 	    exit outer_lock_loop;
301 
302           elsif (wf_item.acquire_lock(l_itemtypeTAB(l_itemtypeTAB.LAST),
303             l_itemkeyTAB(l_itemkeyTAB.LAST), FALSE)) then
304 
305             -- Once we acquired a lock on a last item, copy the last time to
306             -- the current index so that we have a dense index table.
307             l_itemkeyTAB(j) := l_itemkeyTAB(l_itemkeyTAB.LAST);
308             l_itemkeyTAB.DELETE(l_itemkeyTAB.LAST);
309             exit lock_loop;
310           else
311             xenddate := l_enddateTAB(l_itemkeyTAB.LAST);
312             l_itemkeyTAB.DELETE(l_itemkeyTAB.LAST);
313           end if;
314         end loop lock_loop;
315       end if;
316     end loop outer_lock_loop;
317 
318     if (l_itemkeyTAB.COUNT > 0) then
319 
320       FOR j IN l_itemkeyTAB.FIRST..l_itemkeyTAB.LAST loop
321         begin
322           select   WN.NOTIFICATION_ID
323 	  BULK COLLECT into l_tempListTAB
324 	    from   WF_ITEM_ACTIVITY_STATUSES WIAS,
325 	           WF_NOTIFICATIONS WN
326 	    where  WIAS.ITEM_TYPE = l_itemtypeTAB(j)
327 	    and    WIAS.ITEM_KEY  = l_itemkeyTAB(j)
328 	    and    WIAS.NOTIFICATION_ID = WN.GROUP_ID
329             and    ((purgesigs = 1)
330 		    or not exists
331 	            (select null
332                      from   WF_DIG_SIGS WDS
333                      where  SIG_OBJ_TYPE = 'WF_NTF'
334                      and    SIG_OBJ_ID = WN.NOTIFICATION_ID))
335 	   union all
336 	   select WN.NOTIFICATION_ID
337 	    from   WF_ITEM_ACTIVITY_STATUSES_H WIASH,
338 	           WF_NOTIFICATIONS WN
339 	    where  WIASH.ITEM_TYPE = l_itemtypeTAB(j)
340 	    and    WIASH.ITEM_KEY  = l_itemkeyTAB(j)
341 	    and    WIASH.NOTIFICATION_ID = WN.GROUP_ID
342             and    ((purgesigs = 1)
343 		    or not exists
344 	            (select null
345                      from   WF_DIG_SIGS WDS
346                      where  SIG_OBJ_TYPE = 'WF_NTF'
347                      and    SIG_OBJ_ID = WN.NOTIFICATION_ID));
348 
349 	  if (l_tempListTAB.COUNT > 0) then
350 	    FOR i IN l_tempListTAB.FIRST..l_tempListTAB.LAST loop
351                 l_nidListTAB(l_nidListTAB.COUNT + 1) := l_tempListTAB(i);
352 	    end loop;
353 	  end if;
354 	end;
355       end loop;
356 
357       if (l_nidListTAB.COUNT > 0) then
358         begin
359           FORALL i IN l_nidListTAB.FIRST..l_nidListTAB.LAST
360             -- now delete each notification
361             delete from WF_NOTIFICATION_ATTRIBUTES WNA
362             where WNA.NOTIFICATION_ID = l_nidListTAB(i);
363 
364           --<rwunderl:3751558>
365           -- Delete the signatures related to this notification
366           -- Bug 4163328
367           -- Check if Wf_Digital_Security_Private.Purge_Signature_By_Obj_I is
368           -- accepting varray, if not don't run it again.
369 	  if purgesigs=1 then
370           FOR i in l_nidListTAB.FIRST..l_nidListTAB.LAST loop
371 	    if (l_signature) then
372               begin
373                 execute IMMEDIATE 'begin Wf_Digital_Security_Private.Purge_Signature_By_Obj_Id(''WF_NTF'', :1); end;'
374                   using to_char(l_nidListTAB(i));
375 
376               exception
377                 when invalid_identifier then
378                   l_signature := FALSE;
379 
380                 when invalid_component then
381                   l_signature := FALSE;
382               end;
383               --</rwunderl:3751558>
384             end if;
385           end loop;
386 	  end if;
387 
388             FORALL i in l_nidListTAB.FIRST..l_nidListTAB.LAST
389             -- Delete notification comments
390             DELETE FROM wf_comments wc
391             WHERE wc.notification_id = l_nidListTAB(i);
392 
393             begin
394               FORALL i in l_nidListTAB.FIRST..l_nidListTAB.LAST
395               delete from WF_NOTIFICATIONS WN
396               where WN.NOTIFICATION_ID = l_nidListTAB(i);
397             exception when in_other_status_table then
398               -- happens when nid is also in history table
399               -- we will delete this later in the loop
400               null;
401             end;
402 
403          -- clear l_nidListTAB index table for next bulk processing
404          FOR i IN l_nidListTAB.FIRST..l_nidListTAB.LAST loop
405            l_nidListTAB.DELETE(i);
406          end loop;
407         exception
408 	  when others then
409         rollback;
410         end;
411       end if;  --if (l_nidListTAB.COUNT > 0)
412 
413        begin
414          --delete all status history.
415          FORALL j IN l_itemkeyTAB.FIRST..l_itemkeyTAB.LAST
416          delete from WF_ITEM_ACTIVITY_STATUSES_H
417            where ITEM_TYPE = l_itemtypeTAB(j)
418            and   ITEM_KEY  = l_itemkeyTAB(j);
419 
420          --delete all statuses.
421          FORALL j IN l_itemkeyTAB.FIRST..l_itemkeyTAB.LAST
422          delete from WF_ITEM_ACTIVITY_STATUSES
423            where ITEM_TYPE = l_itemtypeTAB(j)
424            and   ITEM_KEY  = l_itemkeyTAB(j);
425 
426          --delete item attributes
427          FORALL j IN l_itemkeyTAB.FIRST..l_itemkeyTAB.LAST
428          delete from  WF_ITEM_ATTRIBUTE_VALUES
429            where ITEM_TYPE = l_itemtypeTAB(j)
430            and   ITEM_KEY  = l_itemkeyTAB(j);
431 
432 -- 3966635 Workflwo Provisioning Project
433 -- Following added so as not to loose the changes required.
434 --          --delete Provision Requests, if any
435 --          delete from WF_PROV_REQUESTS
436 --          where CONTEXT like c_item_type||':'||c_item_key||':'||'%'
437 --            and source = 'WORKFLOW';
438 --
439          --finally delete the item itself.
440          FORALL j IN l_itemkeyTAB.FIRST..l_itemkeyTAB.LAST
441          delete from  WF_ITEMS
442            where ITEM_TYPE = l_itemtypeTAB(j)
443            and   ITEM_KEY  = l_itemkeyTAB(j);
444 
445       exception
446         when others then
447         rollback;
448       end;
449 
450       --<rwunderl:3751558>
451       begin
452         execute immediate l_ecx_sql using  itemtype, itemkey, enddate;
453       exception
454         when invalid_identifier then
455           null;
456 
457         when invalid_component then
458           null;
459        end;
460       --</rwunderl:3751558>
461     end if;
462 
463     if (l_keycount >= wf_purge.commit_frequency) then
464       exit item_purge_loop;
465     elsif (l_keycount < wf_purge.commit_frequency) then
466       exit outer_purge;
467     end if;
468 
469     end loop item_purge_loop; -- item2purge or item3purge loop
470 
471       if (item2purge%ISOPEN) then
472         close item2purge;
473       end if;
474 
475       if (item3purge%ISOPEN) then
476         close item3purge;
477       end if;
478 
479       if (item4purge%ISOPEN) then
480         close item4purge;
481       end if;
482 
483       -- CTILLEY bug 3228475
484       if (item5purge%ISOPEN) then
485         close item5purge;
486       end if;
487 
488       if ( docommit ) then
489         commit;
490         fnd_concurrent.set_preferred_rbs;
491       end if;
492 
493   end loop outer_purge;
494 
495   if ( docommit ) then
496     commit;
497     fnd_concurrent.set_preferred_rbs;
498   end if;
499 
500   if (item2purge%ISOPEN) then
501     close item2purge;
502   end if;
503 
504   if (item3purge%ISOPEN) then
505     close item3purge;
506   end if;
507 
508   if (item4purge%ISOPEN) then
509        close item4purge;
510   end if;
511 
512   -- CTILLEY bug 3228475
513   if (item5purge%ISOPEN) then
514          close item5purge;
515   end if;
516 
517   -- Clear engine runtime cache for convenience
518   Wf_Item.ClearCache;
519 
520 exception
521   when others then
522     if (item2purge%ISOPEN) then
523       close item2purge;
524     end if;
525 
526     if (item3purge%ISOPEN) then
527       close item3purge;
528     end if;
529 
530     if (item4purge%ISOPEN) then
531        close item4purge;
532     end if;
533 
534     -- CTILLEY bug 3228475
535     if (item5purge%ISOPEN) then
536            close item5purge;
537     end if;
538 
539 
540     Wf_Core.Context('Wf_Purge', 'Items', itemtype, itemkey, to_char(enddate));
541     raise;
542 end Items;
543 
544 --
545 -- procedure Activities
546 --   Delete old activity versions with end_time before argument,
547 --   and that are not referenced by an existing item.
548 -- IN:
549 --   itemtype - Item type to delete, or null for all itemtypes
550 --   name - Activity to delete, or null for all activities
551 --   enddate - Date to obsolete to
552 -- NOTE:
553 --   It is recommended to purge Items before purging Activities to avoid
554 --   obsolete item references preventing obsolete activities from being
555 --   deleted.
556 --
557 procedure Activities(
558   itemtype in varchar2,
559   name in varchar2,
560   enddate in date)
561 is
562   type typetab is table of varchar2(8) index by binary_integer;
563   type nametab is table of varchar2(30) index by binary_integer;
564 
565   -- Select all activities of this itemtype
566 
567 
568   cursor actcurs1 is
569     select distinct WA.ITEM_TYPE, WA.NAME
570     from WF_ACTIVITIES WA
571     where WA.ITEM_TYPE = itemtype;
572 
573   cursor actcurs2 is
574     select distinct WA.ITEM_TYPE, WA.NAME
575     from WF_ACTIVITIES WA
576     where WA.ITEM_TYPE = itemtype
577     and WA.NAME = name;
578 
579   cursor actcurs3 is
580     select distinct WA.ITEM_TYPE, WA.NAME
581     from WF_ACTIVITIES WA;
582 
583 
584   /* JWSMITH BUG 2208127 - took out decode statment as this was   */
585   /* preventing stats from being used and causing performance */
586   /* issues.  Instead have two cursors and if logic to decide     */
587   /* between them.  See bug for more details.                     */
588   cursor parentcurs1(acttype in varchar2, actname in varchar2) is
589     select WPA.PROCESS_ITEM_TYPE, WPA.PROCESS_NAME
590     from WF_PROCESS_ACTIVITIES WPA
591     where WPA.ACTIVITY_ITEM_TYPE = acttype
592     and WPA.ACTIVITY_NAME = actname
593     union
594     select WA.ITEM_TYPE PROCESS_ITEM_TYPE, WA.NAME PROCESS_NAME
595     from WF_ACTIVITIES WA
596     where WA.ERROR_ITEM_TYPE = acttype
597     and WA.ERROR_PROCESS IS NOT NULL;
598 
599   -- Select processes using an activity in any version,
600   -- or referencing this activity as an error process
601   cursor parentcurs2(acttype in varchar2, actname in varchar2) is
602     select WPA.PROCESS_ITEM_TYPE, WPA.PROCESS_NAME
603     from WF_PROCESS_ACTIVITIES WPA
604     where WPA.ACTIVITY_ITEM_TYPE = acttype
605     and WPA.ACTIVITY_NAME = actname
606     union
607     select WA.ITEM_TYPE PROCESS_ITEM_TYPE, WA.NAME PROCESS_NAME
608     from WF_ACTIVITIES WA
609     where WA.ERROR_ITEM_TYPE = acttype
610     and WA.ERROR_PROCESS = actname;
611 
612 parent parentcurs1%rowtype;
613 parent1 parentcurs2%rowtype;
614 
615   -- Select all versions of an activity before given enddate
616   cursor vercurs(acttype in varchar2, actname in varchar2) is
617     select WA.BEGIN_DATE, WA.END_DATE, WA.VERSION
618     from WF_ACTIVITIES WA
619     where WA.ITEM_TYPE = acttype
620     and WA.NAME = actname
621     and exists
622       (select null
623       from WF_ITEM_TYPES WIT
624       where WA.END_DATE+nvl(WIT.PERSISTENCE_DAYS,0)<=enddate
625       and WA.ITEM_TYPE = WIT.NAME
626       and WIT.PERSISTENCE_TYPE = Wf_Purge.persistence_type);
627 
628   --Use itemcurs1 if the rootname is 'ROOT'
629   cursor itemcurs1(begdate in date, enddate in date,
630                    roottype in varchar2, rootname in varchar2) is
631     select WI.ITEM_TYPE, WI.ITEM_KEY, WI.ROOT_ACTIVITY, WI.BEGIN_DATE
632     from WF_ITEMS WI
633     where WI.BEGIN_DATE between begdate and  nvl(enddate, WI.BEGIN_DATE)
634     and WI.ITEM_TYPE     = roottype;
635 
636   --Use itemcurs2 for other rootnames
637   cursor itemcurs2(begdate in date, enddate in date,
638                   roottype in varchar2, rootname in varchar2) is
639     select WI.ITEM_TYPE, WI.ITEM_KEY, WI.ROOT_ACTIVITY, WI.BEGIN_DATE
640     from WF_ITEMS WI
641     where WI.BEGIN_DATE between begdate and  nvl(enddate, WI.BEGIN_DATE)
642     and WI.ITEM_TYPE     = roottype
643     and WI.ROOT_ACTIVITY = rootname ;
644 
645    item itemcurs1%rowtype;
646    item1 itemcurs2%rowtype;
647 
648   -- List of processes/activities yet to be checked
649   checkcur  pls_integer;
650   checkmax  pls_integer;
651   checktype typetab;
652   checkname nametab;
653 
654   -- List of processes already checked
655   foundmax  pls_integer;
656   foundtype typetab;
657   foundname nametab;
658 
659   -- List of possible root processes found
660   rootmax  pls_integer;
661   roottype typetab;
662   rootname nametab;
663 
664   found boolean;
665 
666   rootid pls_integer;
667   refflag boolean;
668 
669   numvers pls_integer;
670 
671   c_item_type varchar2(8);
672   c_name varchar2(30);
673 
674 begin
675 
676 
677   -- Disallow future date in enddate
678   -- Avoid something being purged before its defined persistence period.
679   if (enddate > sysdate) then
680     Wf_Core.Token('SYSDATE', to_char(sysdate));
681     Wf_Core.Raise('WF_FUTURE_END_DATE');
682   end if;
683 
684    -- Bug 3228475 Disallow partial values for itemtype and activity name
685    if ((itemtype is not null and (instr(name,'%')>0 or itemtype is null))
686        or (instr(itemtype,'%')>0)) then
687       Wf_Core.Raise('WFSQL_ARGS');
688    end if;
689 <<outer_actloop>>
690 loop
691   if (itemtype is not null and name is null) then
692         open actcurs1;
693   elsif (itemtype is not null) then
694         open actcurs2;
695   else
696         open actcurs3;
697   end if;
698 
699    <<actloop>>
700    loop
701 
702     if (itemtype is not null and name is null) then
703        fetch actcurs1 into  c_item_type, c_name;
704          if (actcurs1%notfound) then
705              exit outer_actloop;
706          end if;
707     elsif (itemtype is not null) then
708           fetch actcurs2 into  c_item_type, c_name;
709   	  if (actcurs2%notfound) then
710              exit outer_actloop;
711           end if;
712     else
713           fetch actcurs3 into  c_item_type, c_name;
714   	  if (actcurs3%notfound) then
715              exit outer_actloop;
716           end if;
717     end if;
718 
719 
720     -- Build table of all possible root processes referencing this activity.
721     -- Start with only this activity on the check list,
722     -- and the found and root lists empty.
723     checkcur := 1;
724     checkmax := 1;
725     checktype(1) := c_item_type;
726     checkname(1) := c_name;
727     foundmax := 0;
728     rootmax := 0;
729 
730     -- While processes left to check...
731     <<checkloop>>
732     while (checkcur <= checkmax) loop
733       -- JWSMITH BUG 2208127, Determine which cursor to use.
734       if (checkname(checkcur) = 'ROOT') then
735          -- If this node is already a root, add it to the list immediately.
736          rootmax := rootmax + 1;
737          roottype(rootmax) := checktype(checkcur);
738          rootname(rootmax) := checkname(checkcur);
739 
740          open parentcurs1(checktype(checkcur),checkname(checkcur));
741       else
742          open parentcurs2(checktype(checkcur),checkname(checkcur));
743       end if;
744 
745       -- Get all processes referencing this activity
746       <<parentloop>>
747 
748       -- JWSMITH BUG 2208127, Determine which cursor to use.
749       loop
750 
751         if (checkname(checkcur) = 'ROOT') then
752            fetch parentcurs1 into parent;
753            EXIT WHEN parentcurs1%NOTFOUND;
754         else
755            fetch parentcurs2 into parent1;
756            EXIT WHEN parentcurs2%NOTFOUND;
757            parent := parent1;
758         end if;
759         if (parent.process_name = 'ROOT') then
760            -- If we have reached a root node, add this to this list
761            -- of root processes to check.
762            rootmax := rootmax + 1;
763            roottype(rootmax) := checktype(checkcur);
764            rootname(rootmax) := checkname(checkcur);
765         else
766            -- Otherwise, check if we have already found this activity
767            -- (Found means it has either already been checked or is
768            -- currently in the check queue.)
769            found := FALSE;
770            <<foundloop>>
771            for i in 1 .. foundmax loop
772               if ((foundtype(i) = parent.process_item_type) and
773                  (foundname(i) = parent.process_name)) then
774                   found := TRUE;
775                   exit foundloop;
776               end if;
777            end loop foundloop;
778            -- This is the first time this process has been found.
779            -- Add it to the found list and the list of further
780            -- processes to check.
781            if (not found) then
782               -- Add to list of processes found
783               foundmax := foundmax + 1;
784               foundtype(foundmax) := parent.process_item_type;
785               foundname(foundmax) := parent.process_name;
786 
787               -- Add parent process to list to check
788               checkmax := checkmax + 1;
789               checktype(checkmax) := parent.process_item_type;
790               checkname(checkmax) := parent.process_name;
791            end if;
792         end if;  -- end not root child
793       end loop parentloop;
794 
795       if (parentcurs1%ISOPEN) then
796          CLOSE parentcurs1;
797       elsif (parentcurs2%ISOPEN) then
798          CLOSE parentcurs2;
799       end if;
800 
801       checkcur := checkcur + 1;
802     end loop checkloop;
803 
804     -- All versions of this activity ...
805     <<verloop>>
806     for ver in vercurs(c_item_type, c_name) loop
807       refflag := FALSE;
808       -- All root processes in reference table ...
809       <<rootloop>>
810       for i in 1 .. rootmax loop
811         -- All items in this version using this root process
812         if (rootname(i) = 'ROOT') then
813          open itemcurs1(ver.begin_date, ver.end_date,roottype(i),rootname(i));
814         else
815          open itemcurs2(ver.begin_date, ver.end_date,roottype(i),rootname(i));
816         end if;
817 
818         /**
819          ** Use the itemcur1/itemcur2 depending on rootname
820          ** ROOT or not
821          for item in itemcurs(ver.begin_date, ver.end_date,
822             roottype(i), rootname(i)) loop
823          **/
824          <<itemloop>>
825 
826          loop
827 
828          if (rootname(i)= 'ROOT') then
829            fetch itemcurs1 into item;
830            EXIT WHEN itemcurs1%NOTFOUND;
831          else
832            fetch itemcurs2 into item1;
833            EXIT WHEN itemcurs2%NOTFOUND;
834            item := item1;
835          end if;
836 
837         begin
838           -- Search tree for a reference
839           rootid := Wf_Process_Activity.RootInstanceId(item.item_type,
840                         item.item_key, item.root_activity);
841           if (Wf_Process_Activity.IsChild(rootid, c_item_type,
842                   c_name, item.begin_date)) then
843             refflag := TRUE;
844             exit rootloop;
845           end if;
846           exception
847             when others then
848               -- If any errors occur while searching the item, then the
849               -- item process has been somehow corrupted.
850               -- To be on the safe side, assume it might have a reference
851               -- and do not purge this act/version.
852               refflag := TRUE;
853               exit rootloop;
854           end;
855         end loop itemloop;
856         if (itemcurs1%ISOPEN) then
857           CLOSE itemcurs1;
858         elsif (itemcurs2%ISOPEN) then
859           CLOSE itemcurs2;
860         end if;
861       end loop rootloop;
862 
863       if (itemcurs1%ISOPEN) then
864         CLOSE itemcurs1;
865       elsif (itemcurs2%ISOPEN) then
866         CLOSE itemcurs2;
867       end if;
868 
869       if (not refflag) then
870         -- Purge the activity if no reference found
871 
872         -- Delete any process activities and
873         -- their attribute values and transitions
874         delete from WF_ACTIVITY_ATTR_VALUES WAAV
875         where WAAV.PROCESS_ACTIVITY_ID in
876           (select WPA.INSTANCE_ID
877           from WF_PROCESS_ACTIVITIES WPA
878           where WPA.PROCESS_NAME = c_name
879           and WPA.PROCESS_ITEM_TYPE = c_item_type
880           and WPA.PROCESS_VERSION = ver.version);
881 
882         delete from WF_ACTIVITY_TRANSITIONS WAT
883         where WAT.TO_PROCESS_ACTIVITY in
884           (select WPA.INSTANCE_ID
885           from WF_PROCESS_ACTIVITIES WPA
886           where WPA.PROCESS_NAME = c_name
887           and WPA.PROCESS_ITEM_TYPE = c_item_type
888           and WPA.PROCESS_VERSION = ver.version);
889 
890         delete from WF_ACTIVITY_TRANSITIONS WAT
891         where WAT.FROM_PROCESS_ACTIVITY in
892           (select WPA.INSTANCE_ID
893           from WF_PROCESS_ACTIVITIES WPA
894           where WPA.PROCESS_NAME = c_name
895           and WPA.PROCESS_ITEM_TYPE = c_item_type
896           and WPA.PROCESS_VERSION = ver.version);
897 
898         delete from WF_PROCESS_ACTIVITIES WPA
899         where WPA.PROCESS_NAME = c_name
900         and WPA.PROCESS_ITEM_TYPE = c_item_type
901         and WPA.PROCESS_VERSION = ver.version;
902 
903         -- Delete activity attributes and _tl
904         delete from WF_ACTIVITY_ATTRIBUTES_TL WAAT
905         where WAAT.ACTIVITY_NAME = c_name
906         and WAAT.ACTIVITY_ITEM_TYPE = c_item_type
907         and WAAT.ACTIVITY_VERSION = ver.version;
908 
909         delete from WF_ACTIVITY_ATTRIBUTES WAA
910         where WAA.ACTIVITY_NAME = c_name
911         and WAA.ACTIVITY_ITEM_TYPE = c_item_type
912         and WAA.ACTIVITY_VERSION = ver.version;
913 
914         -- Delete from activities table and _tl table.
915         delete from WF_ACTIVITIES_TL WAT
916         where WAT.NAME = c_name
917         and WAT.ITEM_TYPE = c_item_type
918         and WAT.VERSION = ver.version;
919 
920         delete from WF_ACTIVITIES WA
921         where WA.NAME = c_name
922         and WA.ITEM_TYPE = c_item_type
923         and WA.VERSION = ver.version;
924       end if;
925 
926     end loop verloop;
927 
928     -- If no versions of activity are left, clear any references to
929     -- this activity in ROOT folders
930     select count(1)
931     into numvers
932     from WF_ACTIVITIES WA
933     where WA.NAME = c_name
934     and WA.ITEM_TYPE = c_item_type;
935 
936     if (numvers = 0) then
937       delete from WF_PROCESS_ACTIVITIES WPA
938       where WPA.PROCESS_ITEM_TYPE = c_item_type
939       and WPA.PROCESS_NAME = 'ROOT'
940       and WPA.ACTIVITY_ITEM_TYPE = c_item_type
941       and WPA.ACTIVITY_NAME = c_name;
942     end if;
943 
944   end loop actloop;
945 
946 
947   if (actcurs1%ISOPEN) then
948       close actcurs1;
949   end if;
950 
951   if (actcurs2%ISOPEN) then
952       close actcurs2;
953   end if;
954 
955   if (actcurs3%ISOPEN) then
956       close actcurs3;
957   end if;
958 
959   end loop outer_actloop;
960 
961   if (actcurs1%ISOPEN) then
962       close actcurs1;
963   end if;
964 
965   if (actcurs2%ISOPEN) then
966       close actcurs2;
967   end if;
968 
969   if (actcurs3%ISOPEN) then
970       close actcurs3;
971   end if;
972 
973   -- Clear engine runtime cache for convenience
974   Wf_Activity.ClearCache;
975 
976 exception
977   when others then
978   if (actcurs1%ISOPEN) then
979       close actcurs1;
980   end if;
981 
982   if (actcurs2%ISOPEN) then
983       close actcurs2;
984   end if;
985 
986   if (actcurs3%ISOPEN) then
987       close actcurs3;
988   end if;
989     Wf_Core.Context('Wf_Purge', 'Activities', itemtype, to_char(enddate));
990     raise;
991 end Activities;
992 
993 --
994 -- procedure Notifications
995 --   Delete old notifications with end_time before argument,
996 --   and that are not referenced by an existing item.
997 -- IN:
998 --   itemtype - Item type to delete, or null for all itemtypes
999 --   enddate - Date to obsolete to
1000 --   docommit- Do not commit if set to false
1001 -- NOTE:
1002 --   It is recommended to purge Items before purging Notifications to avoid
1003 --   obsolete item references preventing obsolete notifications from being
1004 --   deleted.
1005 --
1006 procedure Notifications(
1007   itemtype in varchar2,
1008   enddate in date,
1009   docommit in boolean,
1010   purgesigs in pls_integer)
1011 is
1012   TYPE nidListTAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
1013   l_nidListTAB nidListTAB;
1014 
1015   -- Cursor to delete all enddated notifications. If the design info for the item
1016   -- is available check for the persistence, if not just delete
1017   cursor c1 is
1018     select WN.NOTIFICATION_ID
1019     from WF_NOTIFICATIONS WN
1020     where WN.MESSAGE_TYPE = itemtype
1021     and not exists
1022       (select NULL
1023       from WF_ITEM_ACTIVITY_STATUSES WIAS
1024       where WIAS.NOTIFICATION_ID = WN.GROUP_ID)
1025     and not exists
1026       (select NULL
1027       from WF_ITEM_ACTIVITY_STATUSES_H WIAS
1028       where WIAS.NOTIFICATION_ID = WN.GROUP_ID)
1029     and (
1030      exists(
1031       select null
1032       from WF_ITEM_TYPES WIT
1033       where WN.END_DATE+nvl(WIT.PERSISTENCE_DAYS,0) <= enddate
1034       and WN.MESSAGE_TYPE = WIT.NAME
1035       and WIT.PERSISTENCE_TYPE = Wf_Purge.persistence_type)
1036      or not exists(
1037       select null
1038       from   WF_ITEM_TYPES WIT
1039       where  WN.MESSAGE_TYPE = WIT.NAME))
1040     and(
1041      (purgesigs = 1)
1042       or not exists
1043       (select null
1044       from   WF_DIG_SIGS WDS
1045       where  SIG_OBJ_TYPE = 'WF_NTF'
1046       and    SIG_OBJ_ID = WN.NOTIFICATION_ID));
1047 
1048    cursor c2 is
1049     select WN.NOTIFICATION_ID
1050     from WF_NOTIFICATIONS WN
1051     where not exists
1052       (select NULL
1053       from WF_ITEM_ACTIVITY_STATUSES WIAS
1054       where WIAS.NOTIFICATION_ID = WN.GROUP_ID)
1055     and not exists
1056       (select NULL
1057       from WF_ITEM_ACTIVITY_STATUSES_H WIAS
1058       where WIAS.NOTIFICATION_ID = WN.GROUP_ID)
1059     and (
1060      exists(
1061       select null
1062       from WF_ITEM_TYPES WIT
1063       where WN.END_DATE+nvl(WIT.PERSISTENCE_DAYS,0) <= enddate
1064       and WN.MESSAGE_TYPE = WIT.NAME
1065       and WIT.PERSISTENCE_TYPE = Wf_Purge.persistence_type)
1066      or not exists(
1067       select null
1068       from   WF_ITEM_TYPES WIT
1069       where  WN.MESSAGE_TYPE = WIT.NAME))
1070     and(
1071       (purgesigs = 1)
1072       or not exists
1073       (select null
1074       from   WF_DIG_SIGS WDS
1075       where  SIG_OBJ_TYPE = 'WF_NTF'
1076       and    SIG_OBJ_ID = WN.NOTIFICATION_ID));
1077 
1078   -- <rwunderl:3751558>
1079   invalid_component exception;
1080   pragma EXCEPTION_INIT(invalid_component, -302);
1081 
1082   invalid_identifier exception;
1083   pragma EXCEPTION_INIT(invalid_identifier, -201);
1084   -- </rwunderl:3751558>
1085 begin
1086 
1087   -- Disallow future date in enddate
1088   -- Avoid something being purged before its defined persistence period.
1089   if (enddate > sysdate) then
1090     Wf_Core.Token('SYSDATE', to_char(sysdate));
1091     Wf_Core.Raise('WF_FUTURE_END_DATE');
1092   end if;
1093 
1094   -- Bug 3228475 Disallow partial values being passed for itemtype
1095   if (instr(itemtype,'%')>0) then
1096       Wf_Core.Raise('WFSQL_ARGS');
1097   end if;
1098 
1099   -- End date all the orphan notifications. This end dates all the notifications
1100   -- generated before the enddate parameter value.
1101   loop
1102     UPDATE wf_notifications wn
1103     SET end_date = nvl(begin_date, to_date('2002/08/01','YYYY/MM/DD')) + 1
1104     WHERE NOT EXISTS
1105       (SELECT NULL
1106        FROM  wf_item_activity_statuses wias
1107        WHERE  wias.notification_id = wn.group_id)
1108     AND NOT EXISTS
1109       (SELECT NULL
1110        FROM  wf_item_activity_statuses_h wiash
1111        WHERE  wiash.notification_id = wn.group_id)
1112     AND wn.end_date is null
1113     AND wn.begin_date <= enddate
1114     AND rownum < Wf_Purge.Commit_Frequency;
1115 
1116     --Bug 6759163 : if statement added to avoid commit when
1117     --'docommit' parameter is false
1118     if (docommit) then
1119       commit;
1120     end if;
1121 
1122     exit when (sql%NOTFOUND);
1123   end loop;
1124 
1125   <<outer_ntf_loop>>
1126   loop
1127 
1128     if (itemtype is not null) then
1129       open c1;
1130     else
1131       open c2;
1132     end if;
1133 
1134     <<inner_ntf_loop>>
1135     loop
1136 
1137      if (itemtype is not null) then
1138      -- Bug 4163328
1139      -- Use bulk operations to improve performance
1140         FETCH c1 BULK COLLECT INTO l_nidListTAB LIMIT wf_purge.commit_frequency;
1141           exit outer_ntf_loop when l_nidListTAB.COUNT = 0;
1142       else
1143         FETCH c2 BULK COLLECT INTO l_nidListTAB LIMIT wf_purge.commit_frequency;
1144           exit outer_ntf_loop when l_nidListTAB.COUNT = 0;
1145        end if;
1146 
1147      -- Delete notification attributes
1148      FORALL j in l_nidListTAB.FIRST..l_nidListTAB.LAST
1149        delete from WF_NOTIFICATION_ATTRIBUTES WNA
1150        where WNA.NOTIFICATION_ID = l_nidListTAB(j);
1151 
1152      --<rwunderl:3751558>
1153      -- Delete the signatures related to this notification
1154      if (purgesigs = 1) then
1155      FOR j in l_nidListTAB.FIRST..l_nidListTAB.LAST loop
1156        begin
1157            execute IMMEDIATE 'begin Wf_Digital_Security_Private.Purge_Signature_By_Obj_Id(''WF_NTF'', :1); end;'
1158                    using to_char(l_nidListTAB(j));
1159        exception
1160          when invalid_identifier then
1161            null;
1162 
1163          when invalid_component then
1164            null;
1165        end;
1166      --</rwunderl:3751558>
1167      end loop;
1168      end if;
1169 
1170      -- Delete Notification comments
1171      FORALL j in l_nidListTAB.FIRST..l_nidListTAB.LAST
1172        DELETE FROM wf_comments wc
1173        WHERE wc.notification_id = l_nidListTAB(j);
1174 
1175      -- Delete notifications
1176      FORALL j in l_nidListTAB.FIRST..l_nidListTAB.LAST
1177        delete from WF_NOTIFICATIONS WN
1178        where WN.NOTIFICATION_ID = l_nidListTAB(j);
1179 
1180      if (l_nidListTAB.COUNT >= wf_purge.commit_frequency) then
1181        exit inner_ntf_loop;
1182      elsif (l_nidListTAB.COUNT < wf_purge.commit_frequency) then
1183        exit outer_ntf_loop;
1184      end if;
1185 
1186     end loop inner_ntf_loop;
1187 
1188     if (c1%ISOPEN) then
1189        close c1;
1190     elsif (c2%ISOPEN) then
1191        close c2;
1192     end if;
1193 
1194     -- Commit Decision
1195     if (docommit) then
1196       commit;
1197       Fnd_Concurrent.Set_Preferred_RBS;
1198     end if;
1199 
1200   end loop outer_ntf_loop;
1201 
1202   if (c1%ISOPEN) then
1203      close c1;
1204   elsif (c2%ISOPEN) then
1205      close c2;
1206   end if;
1207 
1208   -- Commit Decision
1209   if (docommit) then
1210     commit;
1211     Fnd_Concurrent.Set_Preferred_RBS;
1212   end if;
1213 
1214   -- Purge AdHoc Users/Roles/User_Roles
1215   Wf_Purge.AdHocDirectory(enddate);
1216 
1217 exception
1218   when others then
1219     if (c1%ISOPEN) then
1220        close c1;
1221     elsif (c2%ISOPEN) then
1222        close c2;
1223     end if;
1224 
1225     Wf_Core.Context('Wf_Purge', 'Notifications', itemtype, to_char(enddate));
1226     raise;
1227 end Notifications;
1228 
1229 --
1230 -- procedure Item_Notifications
1231 --   Delete notifications sent by a particular item with end_time
1232 --   before argument.
1233 -- IN:
1234 --   itemtype - Item type to delete, or null for all itemtypes
1235 --   itemkey - Item key to delete, or null for all itemkeys
1236 --   enddate - Date to obsolete to
1237 --   docommit- Do not commit if set to false
1238 --
1239 procedure Item_Notifications(
1240   itemtype in varchar2,
1241   itemkey in varchar2,
1242   enddate in date,
1243   docommit in boolean)
1244 is
1245 begin
1246    Null;
1247 end Item_Notifications;
1248 
1249 --
1250 -- Total
1251 --   Delete all obsolete runtime data with end_time before argument.
1252 -- IN:
1253 --   itemtype - Item type to delete, or null for all itemtypes
1254 --   itemkey - Item key to delete, or null for all itemkeys
1255 --   enddate - Date to obsolete to
1256 --   docommit- Commit or no commit after each purge of entitiy
1257 --   runtimeonly - If true only runtime /transaction data purged
1258 --             if false both runtime and design data purged.
1259 --
1260 procedure Total(
1261   itemtype in varchar2,
1262   itemkey in varchar2,
1263   enddate in date,
1264   docommit in boolean,
1265   runtimeonly  in boolean,
1266   purgesigs in pls_integer
1267 )
1268 is
1269 
1270 begin
1271 
1272   -- Disallow future date in enddate
1273   -- Avoid something being purged before its defined persistence period.
1274   if (enddate > sysdate) then
1275     Wf_Core.Token('SYSDATE', to_char(sysdate));
1276     Wf_Core.Raise('WF_FUTURE_END_DATE');
1277   end if;
1278 
1279   -- Bug 3228475  Disallow partial values from being passed
1280   if ((itemkey is not null and (instr(itemkey,'%')>0 or itemtype is null))
1281        or (instr(itemtype,'%')>0)) then
1282       Wf_Core.Raise('WFSQL_ARGS');
1283   end if;
1284 
1285  -- Bug 1636510
1286  -- Before attempting to purge items we will abort any error process
1287  -- if the activity that launched it is now complete.
1288   wf_purge.abortErrorProcess(itemtype, itemkey);
1289 
1290   l_docommit := docommit;
1291   l_runtimeonly := runtimeonly;
1292   wf_purge.items(itemtype=>itemtype, itemkey=>itemkey, enddate=>enddate, docommit=>docommit,purgesigs=>purgesigs);
1293 
1294   if (docommit) then
1295     commit;
1296     Fnd_Concurrent.Set_Preferred_RBS;
1297   end if;
1298 
1299   --Purge design data only if runtime is
1300   --set to false
1301   if (not nvl(runtimeonly,TRUE)) then
1302     --also purge design data from activities
1303     wf_purge.activities(itemtype=>itemtype, enddate=>enddate);
1304     if (docommit) then
1305       commit;
1306       Fnd_Concurrent.Set_Preferred_RBS;
1307     end if;
1308 
1309     --Directory Information
1310     Wf_Purge.Directory(enddate);
1311     if (docommit) then
1312       commit;
1313       Fnd_Concurrent.Set_Preferred_RBS;
1314     end if;
1315   end if;
1316 
1317   -- Clear engine runtime cache for convenience
1318   Wf_Item.ClearCache;
1319 
1320   -- Purge orphan notifications only if runtimeonly is false
1321   if (not nvl(runtimeonly, TRUE)) then
1322     --Bug 6759163 : 'docommit' parameter passed to Notifications() as well
1323     Notifications(itemtype=>itemtype, enddate=>enddate,docommit=>docommit,purgesigs=>purgesigs);
1324   end if;
1325 exception
1326   when others then
1327     Wf_Core.Context('Wf_Purge', 'Total', itemtype, itemkey, to_char(enddate));
1328     raise;
1329 end Total;
1330 
1331 --
1332 -- TotalPERM
1333 --   Delete all obsolete runtime data that is of persistence type 'PERM'
1334 --   and with end_time before argument.
1335 -- IN:
1336 --   itemtype - Item type to delete, or null for all itemtypes
1337 --   itemkey - Item key to delete, or null for all itemkeys
1338 --   enddate - Date to obsolete to
1339 --   docommit- Commit or no commit after each purge of entitiy
1340 --   runtimeonly - Delete runtime data alone if set to true
1341 --             else delete both design and runtime data
1342 --
1343 procedure TotalPERM(
1344   itemtype in varchar2,
1345   itemkey in varchar2,
1346   enddate in date,
1347   docommit in boolean,
1348   runtimeonly in boolean,
1349   purgesigs in pls_integer)
1350 is
1351 begin
1352   wf_purge.persistence_type := 'PERM';
1353 
1354   -- Call Total with new args
1355   Wf_Purge.Total(
1356     itemtype,
1357     itemkey,
1358     enddate,
1359     docommit,
1360     nvl(runtimeonly, TRUE),
1361     purgesigs);
1362 
1363   -- Reset persistence type to the default value
1364   wf_purge.persistence_type := 'TEMP';
1365 
1366 exception
1367   when others then
1368     -- Reset persistence type to the default value
1369     wf_purge.persistence_type := 'TEMP';
1370     Wf_Core.Context('Wf_Purge', 'TotalPERM', itemtype, itemkey,
1371                     to_char(enddate));
1372     raise;
1373 end TotalPERM;
1374 
1375 
1376 --
1377 -- TotalConcurrent
1378 --   Concurrent Program version of Total
1379 -- IN:
1380 --   errbuf - CPM error message
1381 --   retcode - CPM return code (0 = success, 1 = warning, 2 = error)
1382 --   itemtype - Item type to delete, or null for all itemtypes
1383 --   itemkey - Item key to delete, or null for all itemkeys
1384 --   age - Minimum age of data to purge (in days)
1385 --   x_persistence_type - Persistence Type to be purged: 'TEMP' or 'PERM'
1386 --   runtimeonly - If 'Y' then purge runtime data alone
1387 --
1388 procedure TotalConcurrent(
1389   errbuf out NOCOPY varchar2,
1390   retcode out NOCOPY varchar2,
1391   itemtype in varchar2,
1392   itemkey in varchar2,
1393   age in varchar2,
1394   x_persistence_type in varchar2,
1395   runtimeonly  in varchar2,
1396   x_commit_frequency in number,
1397   purgesigs in varchar2)
1398 is
1399   enddate date;
1400   errname varchar2(30);
1401   errmsg varchar2(2000);
1402   errstack varchar2(2000);
1403 
1404   l_runtimeonly boolean := FALSE;
1405   l_purgesigs pls_integer;
1406 begin
1407   -- Convert arguments from varchar2 to real type.
1408   enddate := sysdate - to_number(age);
1409 
1410   wf_purge.persistence_type := x_persistence_type;
1411   wf_purge.commit_frequency := x_commit_frequency;
1412 
1413   --If runtimeonly 'N' then purge both runtime
1414   --and design data
1415   if (upper(runtimeonly) = 'Y') then
1416      l_runtimeonly := TRUE;
1417   end if;
1418 
1419   if (upper(purgesigs) = 'Y') then
1420      l_purgesigs := 1;
1421   end if;
1422 
1423    -- Call Total with new args
1424    Wf_Purge.Total(
1425     itemtype,
1426     itemkey,
1427     enddate,
1428     true,
1429     l_runtimeonly,
1430     l_purgesigs);
1431 
1432 
1433   -- Return 0 for successful completion.
1434   errbuf := '';
1435   retcode := '0';
1436   wf_purge.persistence_type := 'TEMP';  -- reset to the default value
1437   wf_purge.commit_frequency := 1000; -- reset to the default value
1438 
1439 exception
1440   when others then
1441     -- Retrieve error message into errbuf
1442     wf_core.get_error(errname, errmsg, errstack);
1443     if (errmsg is not null) then
1444       errbuf := errmsg;
1445     else
1446       errbuf := sqlerrm;
1447     end if;
1448 
1449     -- Return 2 for error.
1450     retcode := '2';
1451 
1452     -- Reset persistence type to the default value
1453     wf_purge.persistence_type := 'TEMP';
1454 end TotalConcurrent;
1455 
1456 --
1457 -- Directory
1458 --   Purge all WF_LOCAL_* tables based on expiration date
1459 -- IN:
1460 --   end_date - Date to purge to
1461 --
1462 procedure Directory(
1463   end_date in date default sysdate,
1464   orig_system in varchar2 default null)
1465 is
1466   --
1467   -- All roles that past the end_date and with no outstanding notification
1468   --
1469   -- Need to check ORIGINAL_RECIPIENT as well as the RECIPIENT_ROLE just
1470   -- in case a 'Delegate' happened, we won't purge the orginal owner.
1471   --
1472   cursor role_cursor is
1473     select local.NAME, local.ORIG_SYSTEM, local.ORIG_SYSTEM_ID,
1474            local.USER_FLAG
1475      from  WF_LOCAL_ROLES local
1476      where PARTITION_ID = 0
1477      and   ORIG_SYSTEM in ('WF_LOCAL_ROLES', 'WF_LOCAL_USERS')
1478      and   EXPIRATION_DATE <= end_date
1479      and not exists
1480            (select NULL
1481             from   WF_ROLE_HIERARCHIES
1482             where  SUPER_NAME = local.NAME
1483             or     SUB_NAME   = local.NAME)
1484      and not exists
1485            (select NULL
1486               from WF_NOTIFICATIONS wn
1487              where wn.RECIPIENT_ROLE = local.NAME
1488                 or wn.ORIGINAL_RECIPIENT = local.NAME);
1489 
1490 
1491   cursor orig_system_cursor (p_OrigSystem varchar2,
1492                              p_endDate date) is
1493     select local.NAME, local.ORIG_SYSTEM, local.ORIG_SYSTEM_ID,
1494            local.USER_FLAG
1495      from  WF_LOCAL_ROLES local
1496      where PARTITION_ID = 0
1497      and   ORIG_SYSTEM = p_origSystem
1498      and   (p_endDate is NULL or EXPIRATION_DATE <= p_endDate)
1499      and not exists
1500            (select NULL
1501             from   WF_ROLE_HIERARCHIES
1502             where  SUPER_NAME = local.NAME
1503             or     SUB_NAME   = local.NAME)
1504      and not exists
1505            (select NULL
1506             from   WF_USER_ROLE_ASSIGNMENTS
1507             where  USER_NAME = local.NAME
1508             and     RELATIONSHIP_ID <> -1)
1509      and not exists
1510            (select NULL
1511               from WF_NOTIFICATIONS wn
1512              where wn.RECIPIENT_ROLE = local.NAME
1513                 or wn.ORIGINAL_RECIPIENT = local.NAME)
1514      and not exists
1515            (select NULL
1516               from WF_ITEMS wi
1517              where wi.OWNER_ROLE = local.NAME);
1518 
1519   rcurs role_cursor%rowtype;
1520   rcurs2 orig_system_cursor%rowtype;
1521 
1522 begin
1523   -- Disallow future date in enddate
1524   -- Avoid something being purged before its expiration date.
1525   if (end_date > sysdate) then
1526     Wf_Core.Token('SYSDATE', to_char(sysdate));
1527     Wf_Core.Raise('WF_FUTURE_END_DATE');
1528   end if;
1529 
1530   if (orig_system is NOT NULL) then
1531     --We are using the new feature allowing a specific orig_system to be
1532     --removed from the local partition either by end_date, or remove all with
1533     --a null end-date (providing there are no active notifications or items).
1534     --
1535     -- Purge Roles
1536     -- Delete rows in wf_local_user_roles by role_name and wf_local_roles
1537     -- by name as determined
1538     for rcurs2 in orig_system_cursor(orig_system, end_date) loop
1539       if (rcurs2.user_flag = 'Y') then
1540         delete from WF_LOCAL_USER_ROLES local
1541          where local.USER_NAME = rcurs2.name
1542            and local.USER_ORIG_SYSTEM = rcurs2.orig_system
1543            and local.USER_ORIG_SYSTEM_ID = rcurs2.orig_system_id;
1544 
1545         delete from WF_USER_ROLE_ASSIGNMENTS local
1546          where local.USER_NAME = rcurs2.name
1547            and local.USER_ORIG_SYSTEM = rcurs2.orig_system
1548            and local.USER_ORIG_SYSTEM_ID = rcurs2.orig_system_id;
1549       else
1550         delete from WF_LOCAL_USER_ROLES local
1551          where local.ROLE_NAME = rcurs2.name
1552            and local.ROLE_ORIG_SYSTEM = rcurs2.orig_system
1553            and local.ROLE_ORIG_SYSTEM_ID = rcurs2.orig_system_id;
1554 
1555         delete from WF_USER_ROLE_ASSIGNMENTS local
1556          where local.ROLE_NAME = rcurs2.name
1557            and local.ROLE_ORIG_SYSTEM = rcurs2.orig_system
1558            and local.ROLE_ORIG_SYSTEM_ID = rcurs2.orig_system_id;
1559 
1560       end if;
1561 
1562       --Remove the role
1563       delete from WF_LOCAL_ROLES local
1564        where local.NAME = rcurs2.name
1565          and local.ORIG_SYSTEM = rcurs2.orig_system
1566          and local.ORIG_SYSTEM_ID = rcurs2.orig_system_id;
1567     end loop;
1568   elsif (end_date is not null) then
1569     --
1570     -- Purge Roles
1571     -- Delete rows in wf_local_user_roles by role_name and wf_local_roles
1572     -- by name as determined
1573     for rcurs in role_cursor loop
1574       if (rcurs.user_flag = 'Y') then
1575         delete from WF_LOCAL_USER_ROLES local
1576          where local.USER_NAME = rcurs.name
1577            and local.USER_ORIG_SYSTEM = rcurs.orig_system
1578            and local.USER_ORIG_SYSTEM_ID = rcurs.orig_system_id;
1579 
1580         delete from WF_USER_ROLE_ASSIGNMENTS local
1581          where local.USER_NAME = rcurs.name
1582            and local.USER_ORIG_SYSTEM = rcurs.orig_system
1583            and local.USER_ORIG_SYSTEM_ID = rcurs.orig_system_id;
1584       else
1585         delete from WF_LOCAL_USER_ROLES local
1586          where local.ROLE_NAME = rcurs.name
1587            and local.ROLE_ORIG_SYSTEM = rcurs.orig_system
1588            and local.ROLE_ORIG_SYSTEM_ID = rcurs.orig_system_id;
1589 
1590         delete from WF_USER_ROLE_ASSIGNMENTS local
1591          where local.ROLE_NAME = rcurs.name
1592            and local.ROLE_ORIG_SYSTEM = rcurs.orig_system
1593            and local.ROLE_ORIG_SYSTEM_ID = rcurs.orig_system_id;
1594 
1595       end if;
1596 
1597       --Remove the role
1598       delete from WF_LOCAL_ROLES local
1599        where local.NAME = rcurs.name
1600          and local.ORIG_SYSTEM = rcurs.orig_system
1601          and local.ORIG_SYSTEM_ID = rcurs.orig_system_id;
1602     end loop;
1603   end if;
1604 exception
1605   when others then
1606     if (role_cursor%isopen) then
1607       close role_cursor;
1608     end if;
1609     wf_core.context('WF_PURGE', 'Directory', end_date);
1610     raise;
1611 end Directory;
1612 
1613 --
1614 -- AdHocDirectory
1615 --   Purge all WF_LOCAL_* tables based on expiration date
1616 -- IN:
1617 --   end_date - Date to purge to
1618 --
1619 procedure AdHocDirectory(
1620   end_date in date)
1621 is
1622 begin
1623   Wf_Purge.Directory(end_date);
1624 exception
1625   when OTHERS then
1626     wf_core.context('WF_PURGE', 'AdHocDirectory', end_date);
1627     raise;
1628 end AdHocDirectory;
1629 
1630  --
1631  -- GetPurgeableCount
1632  --   Returns the count of purgeable items for a specific itemType.
1633  -- IN:
1634  --   p_itemType  in VARCHAR2
1635  --
1636  FUNCTION GetPurgeableCount (p_itemType in varchar2) return number is
1637  l_purgeable number ;
1638  BEGIN
1639     --Get all records for the itemtype
1640      select Count(*) into l_purgeable
1641      from  WF_ITEMS WI
1642      where WI.ITEM_TYPE = p_itemType
1643      and   WI.END_DATE <= sysdate
1644      and  exists
1645          (select null
1646           from WF_ITEM_TYPES WIT
1647           where WI.END_DATE+nvl(WIT.PERSISTENCE_DAYS,0)<=sysdate
1648           and WI.ITEM_TYPE = WIT.NAME
1649           )
1650       and not exists
1651          (select null
1652           from WF_ITEMS WI2
1653           WHERE WI2.END_DATE IS NULL
1654           START WITH WI2.ITEM_TYPE = WI.ITEM_TYPE
1655           AND WI2.ITEM_KEY = WI.ITEM_KEY
1656           CONNECT BY PRIOR WI2.ITEM_TYPE = WI2.PARENT_ITEM_TYPE
1657           AND PRIOR WI2.ITEM_KEY = WI2.PARENT_ITEM_KEY
1658           UNION ALL
1659           select null
1660           from WF_ITEMS WI2
1661           WHERE WI2.END_DATE IS NULL
1662           START WITH WI2.ITEM_TYPE = WI.ITEM_TYPE
1663           AND WI2.ITEM_KEY = WI.ITEM_KEY
1664           CONNECT BY PRIOR WI2.PARENT_ITEM_TYPE = WI2.ITEM_TYPE
1665           AND PRIOR WI2.PARENT_ITEM_KEY = WI2.ITEM_KEY);
1666    return l_purgeable;
1667 exception
1668   when OTHERS then
1669     wf_core.context('WF_PURGE', 'GetPurgeableCount', p_itemType);
1670     raise;
1671 end;
1672 
1673 
1674  --
1675  -- AbortErrorProcess
1676  --   Aborts the Error process for an errored activity if the activity is
1677  --   now COMPLETE.
1678  -- IN:
1679  --   itemtype  in VARCHAR2
1680  --   itemkey   in VARCHAR2
1681  --
1682  procedure AbortErrorProcess (itemtype varchar2,
1683                               itemkey varchar2)
1684  is
1685 
1686   c_item_key varchar2(240);
1687 
1688   cursor c_error1 is
1689     select wi.item_key
1690     from wf_item_activity_statuses wias, wf_items wi
1691     where wi.item_type = 'WFERROR'
1692     and parent_item_type = itemtype
1693     and wi.parent_item_type = wias.item_type
1694     and wi.parent_item_key = wias.item_key
1695     and wi.parent_context = wias.process_activity
1696     and wias.activity_status = 'COMPLETE';
1697 
1698  cursor c_error2 is
1699     select wi.item_key
1700     from wf_item_activity_statuses wias, wf_items wi
1701     where wi.item_type = 'WFERROR'
1702     and parent_item_type = itemtype
1703     and parent_item_key = itemkey
1704     and wi.parent_item_type = wias.item_type
1705     and wi.parent_item_key = wias.item_key
1706     and wi.parent_context = wias.process_activity
1707     and wias.activity_status = 'COMPLETE';
1708 
1709  cursor c_error3 is
1710     select wi.item_key
1711     from wf_item_activity_statuses wias, wf_items wi
1712     where wi.item_type = 'WFERROR'
1713     and wi.parent_item_type = wias.item_type
1714     and wi.parent_item_key = wias.item_key
1715     and wi.parent_context = wias.process_activity
1716     and wias.activity_status = 'COMPLETE';
1717 
1718 
1719  begin
1720 
1721    if ((itemkey is not null and (instr(itemkey,'%')>0 or itemtype is null))
1722       or (instr(itemtype,'%')>0)) then
1723           Wf_Core.Raise('WFSQL_ARGS');
1724    end if;
1725 
1726    -- Outer loop
1727    <<outer_abort>>
1728    loop
1729 
1730       if (itemtype is not null and itemkey is null) then
1731          open c_error1;
1732       elsif (itemtype is not null) then
1733          open c_error2;
1734       else
1735          open c_error3;
1736       end if;
1737 
1738      -- Inner loop
1739      <<abort_loop>>
1740      loop
1741 
1742         if (itemtype is not null and itemkey is null) then
1743            fetch c_error1 into  c_item_key;
1744            if (c_error1%notfound) then
1745               exit outer_abort;
1746            end if;
1747         elsif (itemtype is not null) then
1748            fetch c_error2 into c_item_key;
1749            if (c_error2%notfound) then
1750               exit outer_abort;
1751            end if;
1752         else
1753            fetch c_error3 into c_item_key;
1754            if (c_error3%notfound) then
1755               exit outer_abort;
1756            end if;
1757         end if;
1758 
1759         -- Abort the error process since the activity is now COMPLETE
1760         begin
1761 
1762            wf_engine.abortprocess('WFERROR', c_item_key);
1763 
1764         exception when others then
1765            null;
1766         end;
1767 
1768      end loop abort_loop;
1769 
1770       if (c_error1%ISOPEN) then
1771          close c_error1;
1772       end if;
1773 
1774       if (c_error2%ISOPEN) then
1775          close c_error2;
1776       end if;
1777 
1778       if (c_error3%ISOPEN) then
1779          close c_error3;
1780       end if;
1781 
1782    end loop outer_abort;
1783 
1784       if (c_error1%ISOPEN) then
1785          close c_error1;
1786       end if;
1787 
1788       if (c_error2%ISOPEN) then
1789          close c_error2;
1790       end if;
1791 
1792       if (c_error3%ISOPEN) then
1793          close c_error3;
1794       end if;
1795 
1796   EXCEPTION WHEN OTHERS THEN
1797       if (c_error1%ISOPEN) then
1798          close c_error1;
1799       end if;
1800 
1801       if (c_error2%ISOPEN) then
1802          close c_error2;
1803       end if;
1804 
1805       if (c_error3%ISOPEN) then
1806          close c_error3;
1807       end if;
1808 
1809       Wf_Core.Context('Wf_Purge', 'AbortErrorProcess', itemtype, itemkey);
1810       raise;
1811 
1812  end AbortErrorProcess;
1813 
1814 -- 3966635 Workflow Provisioning Project
1815 -- Following procedures are added in order not to loose the changes
1816 -- required.
1817 --  --
1818 --  -- procedure ProvisionRequests
1819 --  --   Delete old provisiong requests with end_time before argument.
1820 --  --   These provisioning requests are not tied explicity to a item.
1821 --  --   Those requests will be removed with the WF_PURGE.Item API.
1822 --  --
1823 --  -- IN:
1824 --  --   context - The context to match for the requests to remove.
1825 --  --   enddate - Date to obsolete to
1826 --  --   docommit- Do not commit if set to false
1827 --  -- NOTE:
1828 --  --
1829 --  procedure ProvisionRequests(
1830 --    context in varchar2,
1831 --    enddate in date,
1832 --    docommit in boolean)
1833 --  is
1834 --    l_context varchar2(320);
1835 --    l_prov_request_id number;
1836 --
1837 --    cursor c1(c_context in varchar2,
1838 --              c_end_date in date)
1839 --    is
1840 --    select prov_request_id
1841 --    from wf_prov_requests
1842 --    where source = 'EXTERNAL'
1843 --      and context like c_context
1844 --      and (end_date is not null and end_date < c_end_date);
1845 --
1846 --  begin
1847 --
1848 --    if (enddate > sysdate) then
1849 --      wf_core.context('WF_PURGE', 'ProvisionRequests');
1850 --      Wf_Core.Token('SYSDATE', to_char(sysdate));
1851 --      Wf_Core.Raise('WF_FUTURE_END_DATE');
1852 --    end if;
1853 --
1854 --    if context is null or length(context) = 0 then
1855 --      l_context := '%';
1856 --    else
1857 --      l_context := context;
1858 --    end if;
1859 --
1860 --    <<outer_prv_loop>>
1861 --    loop
1862 --
1863 --       open c1(l_context, enddate);
1864 --
1865 --       <<inner_prv_loop>>
1866 --       loop
1867 --          fetch c1 into l_prov_request_id;
1868 --          if c1%notfound then
1869 --             exit outer_prv_loop;
1870 --          end if;
1871 --
1872 --          delete from WF_PROV_REQUESTS
1873 --          where prov_request_id = l_prov_request_id;
1874 --
1875 --          exit inner_prv_loop when
1876 --          ( docommit and (c1%rowcount = wf_purge.commit_frequency));
1877 --
1878 --       end loop inner_prv_loop;
1879 --
1880 --       if c1%isopen then
1881 --          close c1;
1882 --       end if;
1883 --
1884 --       if (docommit) then
1885 --         commit;
1886 --         Fnd_Concurrent.Set_Preferred_RBS;
1887 --       end if;
1888 --
1889 --    end loop outer_prv_loop;
1890 --
1891 --
1892 --    if c1%isopen then
1893 --       close c1;
1894 --    end if;
1895 --
1896 --    if (docommit) then
1897 --      commit;
1898 --      Fnd_Concurrent.Set_Preferred_RBS;
1899 --    end if;
1900 --
1901 --  exception
1902 --    when others then
1903 --      if c1%isopen then
1904 --         close c1;
1905 --      end if;
1906 --      wf_core.context('WF_PURGE','ProvisionRequests', context, enddate);
1907 --  end  ProvisionRequests;
1908 --
1909 -- --
1910 -- -- ProvisionRequestsConcurrent
1911 -- --   Concurrent Program version of Total
1912 -- -- IN:
1913 -- --   errbuf - CPM error message
1914 -- --   retcode - CPM return code (0 = success, 1 = warning, 2 = error)
1915 -- --   itemtype - Item type to delete, or null for all itemtypes
1916 -- --   itemkey - Item key to delete, or null for all itemkeys
1917 -- --   age - Minimum age of data to purge (in days)
1918 -- --   x_persistence_type - Persistence Type to be purged: 'TEMP' or 'PERM'
1919 -- --   runtimeonly - If 'Y' then purge runtime data alone
1920 -- --
1921 -- procedure ProvisionRequestsConcurrent(
1922 --   errbuf out NOCOPY varchar2,
1923 --   retcode out NOCOPY varchar2,
1924 --   context in varchar2,
1925 --   age in varchar2 default 0,
1926 --   x_commit_frequency in number default 500
1927 --   )
1928 -- is
1929 --   enddate date;
1930 --   errname varchar2(30);
1931 --   errmsg varchar2(2000);
1932 --   errstack varchar2(2000);
1933 --
1934 --   l_runtimeonly boolean := FALSE;
1935 -- begin
1936 --   -- Convert arguments from varchar2 to real type.
1937 --   if age is not null and age > 0 then
1938 --     enddate := sysdate - to_number(age);
1939 --   else
1940 --     enddate := sysdate;
1941 --   end if;
1942 --
1943 --
1944 --   if x_commit_frequency is not null or x_commit_frequency > 0 then
1945 --     wf_purge.commit_frequency := x_commit_frequency;
1946 --   end if;
1947 --
1948 --   -- Call provisionrequest with new args
1949 --   Wf_Purge.ProvisionRequests(context,
1950 --                              enddate,
1951 --                              true);
1952 --
1953 --
1954 --   -- Return 0 for successful completion.
1955 --   errbuf := '';
1956 --   retcode := '0';
1957 --   wf_purge.commit_frequency := 500; -- reset to the default value
1958 --
1959 -- exception
1960 --   when others then
1961 --     -- Retrieve error message into errbuf
1962 --     wf_core.get_error(errname, errmsg, errstack);
1963 --     if (errmsg is not null) then
1964 --       errbuf := errmsg;
1965 --     else
1966 --       errbuf := sqlerrm;
1967 --     end if;
1968 --
1969 --     -- Return 2 for error.
1970 --     retcode := '2';
1971 
1972 --     -- Reset commit frequency to the default value
1973 --     wf_purge.commit_frequency := 500;
1974 -- end ProvisionRequestsConcurrent;
1975 
1976 
1977 
1978 end WF_PURGE;