DBA Data[Home] [Help]

PACKAGE BODY: APPS.WF_ITEM

Source


1 package body WF_ITEM as
2 /* $Header: wfengb.pls 120.25.12010000.3 2008/10/28 15:19:48 alepe ship $ */
3 
4 c_itemtype varchar2(8);
5 c_itemkey varchar2(240);
6 
7 c_ondemand boolean;
8 
9 c_root_activity varchar2(30);
10 c_root_activity_version pls_integer;
11 c_begin_date date;
12 c_userkey varchar2(240);
13 
14 --
15 -- ClearCache
16 --   Clear runtime cache
17 --
18 procedure ClearCache
19 is
20 begin
21   wf_item.c_itemtype := '';
22   wf_item.c_itemkey := '';
23   wf_item.c_root_activity := '';
24   wf_item.c_root_activity_version := '';
25   wf_item.c_begin_date := to_date(NULL);
26   wf_item.c_userkey := '';
27 
28   --clear ondemand flag
29   wf_item.c_ondemand := null;
30   -- Clear the synch attribute cache too
31   wf_engine.synch_attr_count := 0;
32 
33 exception
34   when others then
35     Wf_Core.Context('Wf_Item', 'ClearCache');
36     raise;
37 end ClearCache;
38 
39 --
40 -- InitCache (PRIVATE)
41 --   Initialize package cache
42 -- IN
43 --   itemtype - Item type
44 --   itemkey - Item key
45 --
46 procedure InitCache(
47   itemtype in varchar2,
48   itemkey in varchar2,
49   ignore_notfound in boolean default FALSE)
50 
51 is
52   rootid number;
53   status varchar2(8);
54   onDemandFlag wf_activity_attributes.text_default%type;
55 begin
56   -- Check for refresh
57   if ((itemtype = wf_item.c_itemtype) and
58       (itemkey = wf_item.c_itemkey)) then
59     return;
60   end if;
61 
62   -- SYNCHMODE: If
63   --   1. Asking for an item other than the cached one AND
64   --   2. The cached item is a synch process AND
65   --   3. The cached item has not yet completed
66   -- then raise an error.  Other items cannot be accessed until synch
67   -- item completes, because it can't be restarted from db
68   if (wf_item.c_itemkey = wf_engine.eng_synch) then
69     -- Get status of root process of cached item
70     -- Note: If process completed successfully, the last thing in the
71     -- WIAS runtime cache should be the root process, which is the
72     -- only reason this will work.
73     begin
74       rootid := Wf_Process_Activity.RootInstanceId(c_itemtype, c_itemkey,
75                                                   c_root_activity);
76       Wf_Item_Activity_Status.Status(c_itemtype, c_itemkey, rootid, status);
77     exception
78       when others then
79         status := 'x';  -- Treat errors like incomplete process
80     end;
81     if (nvl(status, 'x') <> wf_engine.eng_completed) then
82       Wf_Core.Token('ITEMTYPE', itemtype);
83       Wf_Core.Token('ITEMKEY', itemkey);
84       Wf_Core.Raise('WFENG_SYNCH_ITEM');
85     end if;
86   end if;
87 
88   -- Query new values
89   select WI.ROOT_ACTIVITY, WI.ROOT_ACTIVITY_VERSION, WI.BEGIN_DATE,
90          WI.USER_KEY
91   into wf_item.c_root_activity, wf_item.c_root_activity_version,
92        wf_item.c_begin_date, wf_item.c_userkey
93   from WF_ITEMS WI
94   where WI.ITEM_TYPE = InitCache.itemtype
95   and WI.ITEM_KEY = InitCache.itemkey;
96 
97   -- Save cache key values
98   wf_item.c_itemtype := itemtype;
99   wf_item.c_itemkey := itemkey;
100 
101   --cache ondemand flag
102   -- this could potentially have some impact on the performance as this
103   -- routine is called many times while we are dealing with design time data.
104   -- ondemand is true if the name process #ONDEMANDATTR attribute exist,
105   -- otherwise, it is false.
106   --
107   begin
108     select text_default into onDemandFlag from wf_activity_attributes
109       where activity_item_type = c_itemtype
110       and   activity_name = c_root_activity
111       and   activity_version=c_root_activity_version
112       and   name = '#ONDEMANDATTR';
113 
114     wf_item.c_ondemand := true;
115   exception
116     when no_data_found then
117       wf_item.c_ondemand := false;
118   end;
119 
120 
121 
122 exception
123  when NO_DATA_FOUND then
124   if (ignore_notfound) then
125      WF_ITEM.ClearCache;
126 
127   else
128 
129     Wf_Core.Context('Wf_Item', 'InitCache', itemtype, itemkey);
130     raise;
131 
132   end if;
133 
134   when others then
135     Wf_Core.Context('Wf_Item', 'InitCache', itemtype, itemkey);
136     raise;
137 end InitCache;
138 
139 --
140 -- Attribute_On_Demand
141 --   Set parent ids of an item
142 -- IN
143 --   itemtype - Item type
144 --   itemkey - Item key
145 -- Initialize cache if not already done then return c_ondemand;
146 --
147 
148 function Attribute_On_Demand(
149   itemtype in varchar2,
150   itemkey in varchar2
151 ) return boolean
152 as
153 begin
154   --
155   --we need to call in case itemtype and itemkey are not in synch with
156   --cached value.
157   --
158   Wf_Item.InitCache(itemtype, itemkey, ignore_notfound=>TRUE);
159   return c_ondemand;
160 end Attribute_On_Demand;
161 
162 --
163 -- Set_Item_Parent
164 --   Set parent ids of an item
165 -- IN
166 --   itemtype - Item type
167 --   itemkey - Item key
168 --   parent_itemtype - Itemtype of parent
169 --   parent_itemkey - Itemkey of parent
170 --   parent_context - Context info about parent
171 --
172 procedure Set_Item_Parent(itemtype in varchar2,
173                           itemkey in varchar2,
174                           parent_itemtype in varchar2,
175                           parent_itemkey in varchar2,
176                           parent_context in varchar2,
177                           masterdetail   in boolean)
178 is
179     ValTooLarge EXCEPTION;
180     pragma exception_init(ValTooLarge, -01401);
181 
182 begin
183   update WF_ITEMS set
184     PARENT_ITEM_TYPE = Set_Item_Parent.parent_itemtype,
185     PARENT_ITEM_KEY = Set_Item_Parent.parent_itemkey,
186     PARENT_CONTEXT = Set_Item_Parent.parent_context
187   where ITEM_TYPE = Set_Item_Parent.itemtype
188   and ITEM_KEY = Set_Item_Parent.itemkey;
189 
190   if (sql%notfound) then
191     raise no_data_found;
192   end if;
193 
194   if (masterdetail) then
195     --Increment #WAITFORDETAIL master counter if it exists.
196     if (WF_ENGINE.AddToItemAttrNumber(parent_itemType, parent_itemKey,
197                                       '#WAITFORDETAIL', 1) is NOT NULL) then
198       if (parent_context is NOT null) then
199         --Increment/Create label counter.
200         if (length(parent_context) > 25) then
201           WF_CORE.Token('LABEL', parent_context);
202           WF_CORE.Token('LENGTH', '25');
203           WF_CORE.Raise('WFENG_LABEL_TOO_LARGE');
204 
205         elsif (WF_ENGINE.AddToItemAttrNumber(parent_itemType, parent_itemKey,
206                                              '#CNT_'||parent_context, 1)
207                                               is NULL) then
208           WF_ENGINE.AddItemAttr(itemType=>parent_itemType,
209                                 itemKey=>parent_itemKey,
210                                 aname=>'#CNT_'||parent_context,
211                                 number_value=>1);
212         end if; --Label Counter exists
213 
214         WF_ENGINE.AddItemAttr(itemType=>itemType, itemKey=>itemKey,
215                               aname=>'#LBL_'||parent_context,
216                               text_value=>parent_context);
217 
218       else
219         -- Parent context is null
220         -- increase all known #CNT counter by 1
221         update WF_ITEM_ATTRIBUTE_VALUES
222            set NUMBER_VALUE = NUMBER_VALUE + 1
223          where NAME like '#CNT_%'
224            and NUMBER_VALUE is not null
225            and ITEM_TYPE = parent_itemType
226            and ITEM_KEY = parent_itemKey;
227 
228       end if; --Parent context is not null
229     end if; --#WAITFORDETAIL exists
230   end if; --Caller is signalling that this "should" be a coordinated flow.
231 
232 exception
233   when no_data_found then
234     Wf_Core.Context('Wf_Item', 'Set_Item_Parent', itemtype, itemkey,
235                      parent_itemtype, parent_itemkey, parent_context);
236     Wf_Core.Token('TYPE', itemtype);
237     Wf_Core.Token('KEY', itemkey);
238     Wf_Core.Raise('WFENG_ITEM');
239 
240   when ValTooLarge then
241     Wf_Core.Context('Wf_Item', 'Set_Item_Parent', itemtype, itemkey,
242                      parent_itemtype, parent_itemkey, parent_context, 'TRUE');
243     WF_CORE.Token('LABEL', parent_context);
244     WF_CORE.Token('LENGTH', 25);
245     WF_CORE.Raise('WFENG_LABEL_TOO_LARGE');
246 
247   when others then
248     Wf_Core.Context('Wf_Item', 'Set_Item_Parent', itemtype, itemkey,
249                      parent_itemtype, parent_itemkey, parent_context);
250     raise;
251 end Set_Item_Parent;
252 
253 --
254 -- SetItemOwner
255 --   Set the owner of an item
256 -- IN
257 --   itemtype - Item type
258 --   itemkey - Item key
259 --   owner - Role designated as owner of the item
260 --
261 procedure SetItemOwner(
262   itemtype in varchar2,
263   itemkey in varchar2,
264   owner in varchar2)
265 is
266 begin
267 
268   -- Update owner column
269   update WF_ITEMS WI set
270     OWNER_ROLE = SetItemOwner.owner
271   where WI.ITEM_TYPE = SetItemOwner.itemtype
272   and WI.ITEM_KEY = SetItemOwner.itemkey;
273 
274   if (sql%notfound) then
275     raise no_data_found;
276   end if;
277 exception
278   when no_data_found then
279     Wf_Core.Context('Wf_Item', 'SetItemOwner', itemtype, itemkey,
280                     owner);
281     Wf_Core.Token('TYPE', itemtype);
282     Wf_Core.Token('KEY', itemkey);
283     Wf_Core.Raise('WFENG_ITEM');
284   when others then
285     Wf_Core.Context('Wf_Item', 'SetItemOwner', itemtype, itemkey,
286                     owner);
287     raise;
288 end SetItemOwner;
289 
290 --
291 -- SetItemUserKey
292 --   Set the user key of an item
293 -- IN
294 --   itemtype - Item type
295 --   itemkey - Item key
296 --   userkey - User key to be set
297 --
298 procedure SetItemUserKey(
299   itemtype in varchar2,
300   itemkey in varchar2,
301   userkey in varchar2)
302 is
303 begin
304   update WF_ITEMS WI set
305     USER_KEY = SetItemUserKey.userkey
306   where WI.ITEM_TYPE = SetItemUserKey.itemtype
307   and WI.ITEM_KEY = SetItemUserKey.itemkey;
308 
309   if (sql%notfound) then
310     raise no_data_found;
311   end if;
312 
313   -- Set value in the local cache the right item
314   if ((itemtype = wf_item.c_itemtype) and
315       (itemkey = wf_item.c_itemkey)) then
316     wf_item.c_userkey := userkey;
317   end if;
318 exception
319   when no_data_found then
320     Wf_Core.Context('Wf_Item', 'SetItemUserKey', itemtype, itemkey,
321                     userkey);
322     Wf_Core.Token('TYPE', itemtype);
323     Wf_Core.Token('KEY', itemkey);
324     Wf_Core.Raise('WFENG_ITEM');
325   when others then
326     Wf_Core.Context('Wf_Item', 'SetItemUserKey', itemtype, itemkey,
327                     userkey);
328     raise;
329 end SetItemUserKey;
330 
331 --
332 -- GetItemUserKey
333 --   Get the user key of an item
334 -- IN
335 --   itemtype - Item type
336 --   itemkey - Item key
337 -- RETURNS
338 --   User key of the item
339 --
340 function GetItemUserKey(
341   itemtype in varchar2,
342   itemkey in varchar2)
343 return varchar2
344 is
345   buf varchar2(240);
346 begin
347   -- Check first for cached value
348   if ((itemtype = wf_item.c_itemtype) and
349       (itemkey = wf_item.c_itemkey)) then
350     return(wf_item.c_userkey);
351   end if;
352 
353   -- No cached value, go directly to the source
354   select USER_KEY
355   into buf
356   from WF_ITEMS WI
357   where WI.ITEM_TYPE = GetItemUserKey.itemtype
358   and WI.ITEM_KEY = GetItemUserKey.itemkey;
359 
360   return(buf);
361 exception
362   when no_data_found then
363     Wf_Core.Context('Wf_Item', 'GetItemUserKey', itemtype, itemkey);
364     Wf_Core.Token('TYPE', itemtype);
365     Wf_Core.Token('KEY', itemkey);
366     Wf_Core.Raise('WFENG_ITEM');
367   when others then
368     Wf_Core.Context('Wf_Item', 'GetItemUserKey', itemtype, itemkey);
369     raise;
370 end GetItemUserKey;
371 
372 --
373 -- Item_Exist (PRIVATE)
374 --   Returns TRUE if this is an existing item. Otherwise return FALSE.
375 -- IN
376 --   itemtype - item type
377 --   itemkey - item key
378 --
379 function Item_Exist(itemtype in varchar2,
380                     itemkey  in varchar2)
381 return boolean
382 is
383 begin
384 
385   Wf_Item.InitCache(itemtype, itemkey, ignore_notfound=>TRUE);
386 
387   if (wf_item.c_itemtype is not null) then
388 
389      return(TRUE);
390 
391   else
392 
393      return(FALSE);
394 
395   end if;
396 
397 exception
398   when OTHERS then
399     Wf_Core.Context('Wf_Item', 'Item_Exist', itemtype, itemkey);
400     raise;
401 end Item_Exist;
402 
403 --
404 -- Root_Process (PRIVATE)
405 --   If the item exists, wflow out variable will contain the root process
406 --   name for this item key. Otherwise the wflow out variable will be null.
407 -- IN
408 --   itemtype - item type
409 --   itemkey - item key
410 -- OUT
411 --   wflow - root process
412 --   version - root process version
413 --
414 procedure Root_Process(itemtype in varchar2,
415                        itemkey   in varchar2,
416                        wflow out NOCOPY varchar2,
417                        version out NOCOPY number)
418 is
419 begin
420 
421   Wf_Item.InitCache(itemtype, itemkey);
422   wflow := wf_item.c_root_activity;
423   version := wf_item.c_root_activity_version;
424 
425 exception
426   when NO_DATA_FOUND then
427     wflow := '';
428     version := -1;
429   when OTHERS then
430     Wf_Core.Context('Wf_Item', 'Root_Process', itemtype, itemkey);
431     raise;
432 end Root_Process;
433 
434 --
435 -- Create_Item (PRIVATE)
436 --   Create one row in the WF_ITEMS table with the given item type, item key
437 --   and the root process name.
438 -- IN
439 --   itemtype - item type
440 --   itemkey  - item key
441 --   wflow    - root process name for this item key.
442 --   actdate  - active date of item
443 --
444 procedure Create_Item(
445   itemtype in varchar2,
446   itemkey  in varchar2,
447   wflow    in varchar2,
448   actdate  in date,
449   user_key in varchar2,
450   owner_role in varchar2)
451 is
452 
453   rootversion number;
454   rootid number;
455 
456   onDemandFlag wf_activity_attributes.text_default%type;
457   --<rwunderl:2412940>
458   status  PLS_INTEGER;
459   wiaIND  NUMBER;
460   wiavIND NUMBER;
461 
462   cursor attrcurs(itype in varchar2) is
463     select WIA.ITEM_TYPE, WIA.NAME, WIA.TYPE, WIA.SUBTYPE, WIA.FORMAT,
464            WIA.TEXT_DEFAULT, WIA.NUMBER_DEFAULT, WIA.DATE_DEFAULT
465     from   WF_ITEM_ATTRIBUTES WIA
466     where  WIA.ITEM_TYPE = itype;
467 
468 begin
469 
470   rootversion := Wf_Activity.Version(itemtype, wflow, actdate);
471 
472   if (itemkey <> wf_engine.eng_synch) then
473     -- NORMAL: Insert new item and attributes directly in the db
474     insert into WF_ITEMS (
475       ITEM_TYPE,
476       ITEM_KEY,
477       ROOT_ACTIVITY,
478       ROOT_ACTIVITY_VERSION,
479       OWNER_ROLE,
480       PARENT_ITEM_TYPE,
481       PARENT_ITEM_KEY,
482       BEGIN_DATE,
483       END_DATE,
484       USER_KEY
485     ) values (
486       itemtype,
487       itemkey,
488       wflow,
489       rootversion,
490       Create_Item.owner_role,
491       '',
492       '',
493       actdate,
494       to_date(NULL),
495       Create_item.user_key
496     );
497   end if;
498 
499   -- Initialize runtime cache (used in both NORMAL and SYNCHMODE).
500   wf_item.c_itemtype := itemtype;
501   wf_item.c_itemkey := itemkey;
502   wf_item.c_root_activity := wflow;
503   wf_item.c_root_activity_version := rootversion;
504   wf_item.c_begin_date := actdate;
505   wf_item.c_userkey := Create_item.user_key;
506 
507   --
508   --ondemand flag
509   --
510   begin
511     select text_default into onDemandFlag from wf_activity_attributes
512       where activity_item_type = c_itemtype
513       and   activity_name = c_root_activity
514       and   activity_version=c_root_activity_version
515       and   name = '#ONDEMANDATTR';
516     wf_item.c_ondemand := true;
517   exception
518     when no_data_found then
519     wf_item.c_ondemand := false;
520   end;
521 
522   -- Initialize item attributes
523   if (itemkey <> wf_engine.eng_synch) then
524     -- NORMAL: store attributes in table
525    if(not wf_item.c_ondemand) then
526       -- only popluate when the flag is false
527     insert into WF_ITEM_ATTRIBUTE_VALUES (
528       ITEM_TYPE,
529       ITEM_KEY,
530       NAME,
531       TEXT_VALUE,
532       NUMBER_VALUE,
533       DATE_VALUE
534     ) select
535       itemtype,
536       itemkey,
537       WIA.NAME,
538       WIA.TEXT_DEFAULT,
539       WIA.NUMBER_DEFAULT,
540       WIA.DATE_DEFAULT
541     from WF_ITEM_ATTRIBUTES WIA
542     where WIA.ITEM_TYPE = itemtype;
543     end if;
544   else
545     -- SYNCHMODE: store attributes in plsql only
546     for curs in attrcurs(itemtype) loop
547       --Getting the index for the item attribute.
548       WF_CACHE.GetItemAttribute(itemtype, curs.name, status, wiaIND);
549 
550       --Getting the index for the item attribute value
551       WF_CACHE.GetItemAttrValue(itemtype, itemkey, curs.name, status, wiavIND);
552 
553       --Loading the item attribute into cache for synch mode.
554       WF_CACHE.ItemAttributes(wiaIND).ITEM_TYPE      := itemType;
555       WF_CACHE.ItemAttributes(wiaIND).NAME           := curs.name;
556       WF_CACHE.ItemAttributes(wiaIND).TYPE           := curs.type;
557       WF_CACHE.ItemAttributes(wiaIND).SUBTYPE        := curs.subtype;
558       WF_CACHE.ItemAttributes(wiaIND).FORMAT         := curs.format;
559       WF_CACHE.ItemAttributes(wiaIND).TEXT_DEFAULT   := curs.text_default;
560       WF_CACHE.ItemAttributes(wiaIND).NUMBER_DEFAULT := curs.number_default;
561       WF_CACHE.ItemAttributes(wiaIND).DATE_DEFAULT   := curs.date_default;
562 
563       --Loading the item attribute value into cache for use by synch processes
564       --only until we introduce the item locking feature.
565       WF_CACHE.ItemAttrValues(wiavIND).ITEM_TYPE    := itemType;
566       WF_CACHE.ItemAttrValues(wiavIND).ITEM_KEY     := itemKey;
567       WF_CACHE.ItemAttrValues(wiavIND).NAME         := curs.name;
568       WF_CACHE.ItemAttrValues(wiavIND).TEXT_VALUE   := curs.text_default;
569       WF_CACHE.ItemAttrValues(wiavIND).NUMBER_VALUE := curs.number_default;
570       WF_CACHE.ItemAttrValues(wiavIND).DATE_VALUE   := curs.date_default;
571 
572     end loop;
573   end if;
574 
575 exception
576   when DUP_VAL_ON_INDEX then
577     Wf_Core.Context('Wf_Item', 'Create_Item', itemtype, itemkey, wflow);
578     Wf_Core.Token('TYPE', itemtype);
579     Wf_Core.Token('KEY', itemkey);
580     Wf_Core.Raise('WFENG_ITEM_UNIQUE');
581   when OTHERS then
582     Wf_Core.Context('Wf_Item', 'Create_Item', itemtype, itemkey, wflow);
583     raise;
584 end Create_Item;
585 
586 --
587 -- Active_Date (PRIVATE)
588 --   Return the begin date of an item
589 -- IN
590 --   itemtype
591 --   itemkey
592 -- RETURN
593 --   Begin date of item
594 --
595 function Active_Date(itemtype in varchar2,
596                      itemkey in varchar2)
597 return date
598 is
599 begin
600   Wf_Item.InitCache(itemtype, itemkey);
601   return(wf_item.c_begin_date);
602 exception
603   when NO_DATA_FOUND then
604     Wf_Core.Context('Wf_Item', 'Active_Date', itemtype, itemkey);
605     Wf_Core.Token('TYPE', itemtype);
606     Wf_Core.Token('KEY', itemkey);
607     Wf_Core.Raise('WFENG_ITEM');
608   when OTHERS then
609     Wf_Core.Context('Wf_Item', 'Active_Date', itemtype, itemkey);
610 end Active_Date;
611 
612 --Function Acquire_lock (PRIVATE)
613 --This function tries to lock the particular item (for the give
614 --itemtype/itemkey ) in the wf_items table. It returns true if the lock
615 --acquired else returns false.
616 
617 --Here we will not do any error handling but return true/false
618 --for the case of lock_acquired or not . This leaves the caller
619 --the decision of what to do when a resource busy error occurs
620 --(ie FALSE) . For eg : Background engine will ignore it and move
621 --on , WF Engine will raise exception etc.
622 
623 function acquire_lock(itemtype in varchar2,
624                      itemkey in varchar2,
625                      raise_exception in boolean)
626 return boolean
627 is
628   --Bug 2607770
629   --Cursor for acquiring lock
630   cursor itemlock (itemtype varchar2, itemkey varchar2) is
631   select '1'
632   from   wf_items
633   where  item_type = itemtype
634   and    item_key  = itemkey
635   for update nowait;
636 
637   --Define an exception to capture the resource_busy error
638   resource_busy exception;
639   pragma EXCEPTION_INIT(resource_busy,-00054);
640 
641 begin
642   --Acquire lock here by opening the cursor
643   OPEN  itemlock (itemtype,itemkey);
644   --Close the cursor once the lock has been acquired
645   CLOSE itemlock;
646   return TRUE;
647 exception
648   --Capture the exception on resource-busy error
649   when resource_busy then
650     --Lets double check that the cursor is not open
651     if (itemlock%ISOPEN) then
652       CLOSE itemlock;
653     end if;
654     --check the if_raise flag . If its true then raise
655     --the exception
656     --else return false and let the caller decide what to do.
657     if  raise_exception then
658       raise;
659       --If not able to acquire lock return FALSE
660     else
661       return FALSE;
662     end if;
663   when others then
664     --Lets double check that the cursor is not open
665     if (itemlock%ISOPEN) then
666       CLOSE itemlock;
667     end if;
668     --In this case we do not want a TRUE/FALSE return
669     --we just raise the error.
670     Wf_Core.Context('Wf_Item', 'Acquire_lock', itemtype, itemkey);
671     raise;
672 end;
673 
674 --
675 -- SetEndDate (Private)
676 --   Sets end_date and completes any coordinated counter processing.
677 -- IN
678 --   p_itemtype - process item type
679 --   p_itemkey - process item key
680 -- RETURNS
681 --  number
682 -- NOTE:
683 --   This function will return a status of one of the following:
684 --     0 - Item was found, active, and the end_date was set.
685 --     1 - The item was not found. (ERROR)
686 function SetEndDate(p_itemtype in varchar2,
687                     p_itemkey in varchar2) return number
688   is
689     l_parent_itemType VARCHAR2(8);
690     l_parent_itemKey  VARCHAR2(240);
691     l_parent_context  VARCHAR2(2000);
692 
693     TYPE nameTAB is TABLE of VARCHAR2(30) index by binary_integer;
694     attrNames nameTAB;
695 
696     l_result NUMBER;
697     i        NUMBER;
698   begin
699     UPDATE    wf_items
700     SET       end_date = sysdate
701     WHERE     item_type = p_itemType
702     AND       item_key = p_itemKey
703     AND       end_date is NULL
704     RETURNING parent_item_type, parent_item_key, parent_context
705     INTO      l_parent_itemtype, l_parent_itemkey, l_parent_context;
706 
707     if (sql%notfound) then
708       return 1;
709     end if;
710 
711     --We need to perform some counter processing if they exist.
712     if ((l_parent_itemType is NOT null) and
713         (l_parent_itemKey is NOT null)) then
714       if (WF_ENGINE.AddToItemAttrNumber(l_parent_itemType, l_parent_itemKey,
715                                         '#WAITFORDETAIL', -1) is NOT null) then
716         if ((l_parent_context is NOT null) and
717             (WF_ENGINE.GetItemAttrText(p_itemType, p_itemKey,
718                             '#LBL_'||l_parent_context, TRUE) is NOT NULL)) then
719           if (WF_ENGINE.SetItemAttrText2(p_itemType, p_itemKey,
720                                         '#LBL_'||l_parent_context, NULL)) then
721             l_result := WF_ENGINE.AddToItemAttrNumber(l_parent_itemType,
722                                                       l_parent_itemKey,
723                                                       '#CNT_'||l_parent_context,
724                                                       -1);
725           end if;
726         else
727           SELECT TEXT_VALUE
728           bulk collect into attrNames
729           FROM WF_ITEM_ATTRIBUTE_VALUES
730           WHERE ITEM_TYPE = p_itemType
731           AND   ITEM_KEY = p_itemKey
732           AND   NAME like ('#LBL_%')
733           AND   TEXT_VALUE is NOT null;
734 
735           if (attrNames.COUNT > 0) then
736             for i in attrNames.FIRST..attrNames.LAST loop
737               if (WF_ENGINE.SetItemAttrText2(p_itemType, p_itemKey,
738                                              '#LBL_'||attrNames(i), NULL)) then
739                 l_result := WF_ENGINE.AddToItemAttrNumber(l_parent_itemtype,
740                                                           l_parent_itemkey,
741                                                          '#CNT_'||attrNames(i),
742                                                           -1);
743               end if; --#LBL_ exists as expected.
744             end loop;
745           end if; --There are non-null #LBL_ attributes.
746           --<rwunderl:4271715> We need to decrement any #CNT_ attributes
747           --in the parent which the child may not have created the corresponding
748           --#LBL_ (did not arrive) such as in the case of an AbortProcess()
749           SELECT wiav.NAME
750           bulk collect into attrNames
751           FROM WF_ITEM_ATTRIBUTE_VALUES wiav
752           WHERE wiav.ITEM_TYPE = l_parent_itemType
753           AND   wiav.ITEM_KEY = l_parent_itemKey
754           and   wiav.NAME like ('#CNT_%')
755           AND NOT EXISTS (select null
756                           from   wf_item_attribute_values wiav2
757                           where  wiav2.item_type = p_itemType
758                           and    wiav2.item_key = p_itemKey
759                           and    wiav2.name = REPLACE(wiav.name,'#CNT_','#LBL_'));
760            if (attrNames.COUNT > 0) then
761             for i in attrNames.FIRST..attrNames.LAST loop
762               l_result := WF_ENGINE.AddToItemAttrNumber(l_parent_itemtype,
763                                                         l_parent_itemkey,
764                                                         attrNames(i), -1);
765             end loop;
766           end if; --There were unvisited ContinueFlow() activites in the child.
767         end if; --Parent Context
768       end if; --We were able to decrement the #WAITFORDETAIL
769     end if; --This item has a parent.
770     return 0;
771   exception
772     when OTHERS then
773       WF_CORE.Context('WF_ITEM', 'SetEndDate', p_itemType, p_itemKey);
774       raise;
775 
776   end SetEndDate;
777 
778 end WF_ITEM;