DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_DCP

Source


1 package body FND_DCP as
2 /* $Header: AFCPDCPB.pls 120.5 2007/12/28 19:41:22 ckclark ship $ */
3 
4   --
5   -- PRIVATE VARIABLES
6   --
7 
8   DAY	   constant number	:= 86400;	-- In secs
9   EON	   constant number	:= 86400000;	-- 1000 days in secs
10   NTRUE	   constant number	:= 1;
11   NFALSE   constant number	:= 0;
12   SYSADMIN constant number	:= 0;
13   MGRUSRID constant number	:= 4;
14   THRSHLD  constant number	:= 2;		-- PMON method
15   DEFSLEEP constant number	:= 60;		-- PMON method
16   TSTAMP   constant number	:= 1;		-- PMON method
17   FNDCPLK  constant varchar2(8) := 'FNDCPLK_';
18 
19   my_node        varchar2(30);
20   --
21   -- PRIVATE PROCEDURES, FUNCTIONS
22   --
23 
24   /* Private -- inserts info in FND_CONCURRENT_DEBUG_INFO */
25 
26   procedure debug_fnd_dcp (fn  in varchar2,
27                            msg in varchar2,
28                            txn in number default NULL) is
29   pragma AUTONOMOUS_TRANSACTION;
30   userid number;
31   begin
32    select user_id into userid from user_users;
33 
34    insert into fnd_concurrent_debug_info
35      (SESSION_ID, USER_ID, LOGIN_ID, FUNCTION, TIME, ACTION, MESSAGE)
36    values
37      (userenv('SESSIONID'), userid, fnd_global.login_id, fn,
38      sysdate, 'TXN NO '|| nvl(to_char(txn),'NULL'), msg);
39 
40    commit;
41 
42   end debug_fnd_dcp;
43 
44   function get_icm_info (logf in out nocopy varchar2,
45 			 node in out nocopy varchar2,
46 			 inst in out nocopy varchar2)
47 			 return number is
48 
49 	cpid	number(15) := null;
50 
51   begin
52 	select concurrent_process_id,
53                node_name,
54 	       logfile_name,
55 	       db_instance
56 	  into cpid,
57                node,
58 	       logf,
59 	       inst
60 	  from fnd_concurrent_processes
61 	 where concurrent_process_id in (
62 			select max (concurrent_process_id)
63 			  from fnd_concurrent_processes
64 			 where queue_application_id = 0
65 			   and concurrent_queue_id  = 1
66 			   and process_status_code in ('A', 'M', 'K'));
67 
68         if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
69           fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.GET_ICM_INFO',
70                   'ICM info: cpid=' ||cpid||', node='||node||', inst=' ||inst);
71         end if;
72 
73 	return (cpid);
74 
75 	exception
76 	  when others then
77 	    return (null);
78   end get_icm_info;
79 
80 
81   function get_pid_time (ti   in out nocopy number,	-- PMON method
82 			 td   in out nocopy number,
83 			 apid in     number,
84 			 qid  in     number,
85 			 psc1 in     varchar2 default null,
86 			 psc2 in     varchar2 default null,
87 			 psc3 in     varchar2 default null,
88 			 psc4 in     varchar2 default null)
89 			 return number is
90 
91 	cpid	number(15) := null;
92 
93   begin
94 	select nvl (sleep_seconds, DEFSLEEP)
95 	  into ti
96 	  from fnd_concurrent_queues
97 	 where application_id      = apid
98 	   and concurrent_queue_id = qid;
99 
100 	select concurrent_process_id,
101 	       (sysdate - last_update_date) * DAY
102 	  into cpid,
103 	       td
104 	  from fnd_concurrent_processes
105 	 where concurrent_process_id in (
106 			select max (concurrent_process_id)
107 			  from fnd_concurrent_processes
108 			 where queue_application_id = apid
109 			   and concurrent_queue_id  = qid
110 			   and process_status_code in (
111 					psc1, psc2, psc3, psc4))
112 	   for update nowait;
113 
114 	return (cpid);
115 
116 	exception
117 	  when others then
118 	    return (null);
119   end get_pid_time;				-- PMON method
120 
121   -- ### OVERLOADED ###
122   /*------------------------------------------------------------------|
123    | Private: For use by ATG Only. Please use Check_Process_Status or |
124    |          Request_Session_Lock                                    |
125    |------------------------------------------------------------------|
126    | Bug 2093806: The purpose of this overload for Request_Lock is    |
127    | request a lock by a known handle and to offer more flexibility   |
128    | for the call to DBMS_LOCK.Request.  This procedure accepts a     |
129    | timeout value, and lock mode value.  Instead of interpreting the |
130    | return code from DBMS_LOCK.Request as the  parameter "e_code" set|
131    | to NTRUE (1) or NFALSE (0), the parameter "result" is set to the |
132    | return code for interpretation by the calling function.  If      |
133    | result = NULL, indicates when others exception was raised.       |
134    |------------------------------------------------------------------*/
135   procedure request_lock (hndl    in	 varchar2,
136                           lmode   in     number   default null, -- lock mode
137                           timeout in     number   default null,
138 			  result  in out nocopy number) is
139   begin
140 
141         result := NULL;
142 
143         if ((timeout IS NULL) and (lmode IS NULL )) then
144         /*-------------------------------------------------------+
145          | When caller does not specify, use dbms_lock defaults, |
146          | currently MAXWAIT (32767 secs) X_MODE (6-Exclusive)   |
147          +-------------------------------------------------------*/
148 	  result := dbms_lock.request ( lockhandle => hndl );
149         elsif (timeout IS NULL) then
150           result := dbms_lock.request ( lockhandle => hndl,
151                                         lockmode   => lmode );    -- MAXWAIT
152         elsif (lmode IS NULL) then
153           result := dbms_lock.request ( lockhandle  => hndl,
154                                         timeout     => timeout ); -- ULX lock
155         else
156 	  result := dbms_lock.request ( lockhandle  => hndl,
157                                         lockmode    => lmode,
158                                         timeout     => timeout);
159         end if;
160 
161         /*-------------------------------------------------------+
162          | DBMS_LOCK.Request Result codes:                       |
163          | 0 - Success                                           |
164          | 1 - Timeout                                           |
165          | 2 - Deadlock                                          |
166          | 3 - Parameter error                                   |
167          | 4 - Already own lock specified by lockhandle          |
168          | 5 - Illegal lock handle                               |
169          +-------------------------------------------------------*/
170 
171   exception
172      when others then
173        fnd_message.set_name ('FND', 'CP-Generic oracle error');
174        fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
175        fnd_message.set_token ('ROUTINE', 'REQUEST_LOCK (hndl)', FALSE);
176   end request_lock;
177 
178   --
179   -- PUBLIC PROCEDURES, FUNCTIONS
180   --
181 
182   procedure get_lk_handle (apid	  in     number,
183 			   qid	  in     number,
184 			   pid	  in     number,
185 			   hndl	  in out nocopy varchar2,
186 			   e_code in out nocopy number,
187 			   exp_sec in number default 86400000) is
188 
189 	result	number;
190 	lk	varchar2(128);
191 
192   begin
193 	e_code := NTRUE;
194 
195 	hndl := NULL;
196 
197 	if (apid = 0 and qid = 1 and pid = 0) then
198 	  lk := FNDCPLK || 'ICM';
199 	else
200 	  lk := FNDCPLK || apid || '_' || qid || '_' || pid;
201 	end if;
202 
203 	dbms_lock.allocate_unique (lk, hndl, exp_sec);
204 
205 	exception
206 	  when others then
207 	    e_code := NFALSE;
208 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
209 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
210 	    fnd_message.set_token ('ROUTINE', 'get_lk_handle', FALSE);
211   end get_lk_handle;
212 
213   /*------------------------------------------------------------------|
214    | Bug 2093806: The purpose of Request_Session_Lock is to provide   |
215    | an API which can be used for a manager process (ICM, CM, IM, CRM,|
216    | TM) to request it's own lock for the session.  This procedure    |
217    | is not meant to be used for a process (such as an Apps form, OAM |
218    | procedure or ICM in PMON cycle) to check the lock of another     |
219    | process.  This procedure will wait for the default of  MAXWAIT   |
220    | for the RDBMS to grant the requested lock. If the parameters "lk"|
221    | and "hndl" are returned as NULL, then there was a problem. The   |
222    | calling process can analyze the "result" parameter to determine  |
223    | why the request was not granted.                                 |
224    |------------------------------------------------------------------*/
225   procedure request_session_lock (apid	 in     number,
226 			          qid    in     number,
227 			          pid    in     number,
228 			          lk     in out nocopy varchar2,
229 			          hndl   in out nocopy varchar2,
230 			          result in out nocopy number) is
231 	ecode     number;
232 	timeout   number;
233   begin
234 
235         result := null;
236 
237         /*-------------------------------------------------------+
238          | Construct the lock name for out parameter "lk" and    |
239          | set timeout for Request_Lock.                         |
240          +-------------------------------------------------------*/
241 	if (apid = 0 and qid = 1 and pid = 0) then
242 	  lk      := FNDCPLK || 'ICM';
243           timeout := 5;     -- ICM only waits 5 secs for lock request.
244 	else
245 	  lk      := FNDCPLK || apid || '_' || qid || '_' || pid;
246           timeout := null;  -- Others wait MAXWAIT for lock request.
247 	end if;
248 
249         /*-------------------------------------------------------+
250          | Get handle for the request.                           |
251          +-------------------------------------------------------*/
252         get_lk_handle (apid      => apid,
253                        qid       => qid,
254                        pid       => pid,
255                        hndl      => hndl,
256                        e_code    => ecode);
257         if (ecode = NFALSE) then
258         /*-------------------------------------------------------+
259          | Message available in dictionary set by Get_Lk_Handle  |
260          +-------------------------------------------------------*/
261           lk   := null;
262           hndl := null;
263           return;
264         end if;
265 
266         /*-------------------------------------------------------+
267          | Request with mode of exclusive (ULX), with timeout    |
268          +-------------------------------------------------------*/
269         request_lock (hndl    =>     hndl,
270                       lmode   =>     6,
271                       timeout =>     timeout,
272                       result  =>     result);
273 
274         if (result in (0, 4)) then
275           return;
276         else
277           fnd_message.set_name ('FND', 'CONC-DBMS_LOCK.Request result');
278           fnd_message.set_token ('ROUTINE',
279                                  'FND_DCP.REQUEST_SESSION_LOCK', FALSE);
280           fnd_message.set_token ('RESULT',
281                                  nvl(to_char(result),'NULL'), FALSE);
282           lk   := null;
283           hndl := null;
284           return;
285         end if;
286 
287   end request_session_lock;
288 
289   /*------------------------------------------------------------------|
290    | Bug 2093806: The purpose of Check_Process_Status_By_Handle is to |
291    | provide an API which can be used for a process (such as an Apps  |
292    | form, OAM procedure or ICM in PMON cycle) to check the lock of   |
293    | another process (such as ICM, CM, IM, CRM, TM).  This procedure  |
294    | will immediately time out if the RDBMS does not grant the lock.  |
295    | If process is alive, alive = NTRUE(1). Otherwise, alive =        |
296    | NFALSE(0).  Calling process can analyze the "result" parameter to|
297    | determine  why/why not the lock was granted, if desired.         |
298    |------------------------------------------------------------------*/
299   procedure check_process_status_by_handle (hndl   in   varchar2,
300                                             result out  nocopy number,
301                                             alive  out  nocopy number) is
302 
303 	dummy	    number;
304 
305   begin
306 
307         /*-------------------------------------------------------+
308          | Request with mode of row share (ULRS), timeout of 0   |
309          +-------------------------------------------------------*/
310         request_lock (hndl    =>     hndl,
311                       lmode   =>     2,
312                       timeout =>     0,
313                       result  =>     result);
314 
315         if (result = 0) then
316             /*-------------------------------------------------------+
317              | Lock for handle was granted                           |
318              +-------------------------------------------------------*/
319              alive := NFALSE;            -- manager not alive
320              release_lock(hndl, dummy);
321              return;
322         elsif (result = 4) then
323             /*-------------------------------------------------------+
324              | This process owns the lock, it must be alive!         |
325              +-------------------------------------------------------*/
326              alive := NTRUE;
327              release_lock(hndl, dummy);
328              return;
329         elsif (result in (1, 2)) then
330             /*-------------------------------------------------------+
331              | Lock for handle not granted (2 should never occur)    |
332              +-------------------------------------------------------*/
333              alive := NTRUE;             -- manager alive
334              return;
335         else
336             /*-------------------------------------------------------+
337              | Lock for handle not granted:                          |
338              | result = (3 or 5 from DBMS_LOCK.Request or            |
339              |          still NULL from Request_Lock                 |
340              +-------------------------------------------------------*/
341              alive := NTRUE;             -- assume manager alive
342              fnd_message.set_name ('FND', 'CONC-DBMS_LOCK.Request result');
343          fnd_message.set_token ('ROUTINE',
344                                     'FND_DCP.CHECK_PROCESS_STATUS_BY_HANDLE',
345                                     FALSE);
346          fnd_message.set_token ('RESULT',
347                                     nvl(to_char(result), 'NULL'), FALSE);
348 
349         end if;
350 
351   end check_process_status_by_handle;
352 
353   /*------------------------------------------------------------------|
354    | Bug 2093806: The purpose of Check_Process_Status_By_Ids is to    |
355    | provide an API which can be used for a process (such as an Apps  |
356    | form, OAM procedure or ICM in PMON cycle) to check the lock of   |
357    | another process (such as ICM, CM, IM, CRM, TM).  This procedure  |
358    | uses the Application Id, Queue Id, and O/S Pid to construct the  |
359    | named lock for the request. The procedure  will immediately time |
360    | out if the RDBMS does not grant the lock.  If process is alive,  |
361    | alive = NTRUE(1). Otherwise, alive = NFALSE(0). Calling process  |
362    | can analyze the "result" parameter to determine why/why not the  |
363    | lock was granted, if desired.                                    |
364    |------------------------------------------------------------------*/
365   procedure check_process_status_by_ids (apid    in     number,
366                                          qid     in     number,
367                                          pid     in     number,
368                                          result  out    nocopy number,
369                                          alive   out    nocopy number) is
370 
371         hndl        varchar2(128) := NULL;
372 	dummy	    number;
373 
374   begin
375 
376         /*-------------------------------------------------------+
377          | Get handle for the request                            |
378          +-------------------------------------------------------*/
379         get_lk_handle (apid      => apid,
380                        qid       => qid,
381                        pid       => pid,
382                        hndl      => hndl,
383                        e_code    => dummy);
384 
385         /*-------------------------------------------------------+
386          | Check the process' status by the handle               |
387          +-------------------------------------------------------*/
388         check_process_status_by_handle (hndl   => hndl,
389                                         result => result,
390                                         alive  => alive);
391 
392   end check_process_status_by_ids;
393 
394 
395   -- ### OVERLOADED ###
396   /*------------------------------------------------------------------|
397    | Obsolete: Please use Request_Session_Lock, Check_Process_Status  |
398    |           or Check_Process_Status_By_Handle                      |
399    +------------------------------------------------------------------*/
400   procedure request_lock (apid	in     number,
401 			  qid	in     number,
402 			  pid	in     number,
403 			  lk	in out nocopy varchar2,
404 			  hndl	in out nocopy varchar2,
405 			  e_code in out nocopy number) is
406 
407 	result	number;
408         count   number;
409 
410   begin
411 	e_code := NTRUE;
412 
413 	if (apid = 0 and qid = 1 and pid = 0) then
414 	  lk := FNDCPLK || 'ICM';
415 	else
416 	  lk := FNDCPLK || apid || '_' || qid || '_' || pid;
417 	end if;
418 
419 	dbms_lock.allocate_unique (lk, hndl, EON);
420 	result := dbms_lock.request (hndl, 6, 0);  -- ULX lock
421 
422 	if (result in (0, 4)) then	-- Success or own lock
423 	  return;
424 	elsif (result in (1, 2)) then	-- Timeout or deadlock
425 
426           /* ------------------------------------------------------- */
427           /* Bug 1967288: Timout occasionally returned when manager  */
428           /* log backs into database with afpcsq(). So, try up to 2  */
429           /* more times with 5 second timeout.                       */
430           /* We cannot wait much longer since Forms and OAM use this */
431           /* version of Request_Lock to check each manager's status  */
432           /* This is a short-term fix until more robust restructuring*/
436 	  for count in 1..2 loop
433           /* can be done with lock management procedures, functions. */
434           /* ------------------------------------------------------- */
435 
437 	    result := dbms_lock.request (hndl, 6, 5);
438 	    exit when result in (0, 4);
439 	  end loop;
440 
441 	  if (result in (0, 4)) then	-- Success or own lock
442 	    return;
443 	  elsif (result in (1, 2)) then	-- Timeout or deadlock
444 	      lk := null;
445 	      hndl := null;
446 	  else                          -- Bad lock handle or bad param
447 	      lk   := null;
448 	      hndl := null;
449 	      e_code := NFALSE;
450 	  end if;
451 
452 	else				-- Bad lock handle or bad param
453 	  lk   := null;
454 	  hndl := null;
455 	  e_code := NFALSE;
456 	end if;
457 
458 	exception
459 	  when others then
460 	    e_code := NFALSE;
461 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
462 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
463 	    fnd_message.set_token ('ROUTINE', 'REQUEST_LOCK', FALSE);
464   end request_lock;
465 
466   -- ### OVERLOADED ###
467   /*------------------------------------------------------------------|
468    | Obsolete: Please use Request_Session_Lock, Check_Process_Status  |
469    |           or Check_Process_Status_By_Handle                      |
470    +------------------------------------------------------------------*/
471   procedure request_lock (hndl   in	varchar2,
472 			  status in out nocopy number,
473 			  e_code in out nocopy number) is
474 
475 	result	number;
476 
477   begin
478 	e_code := NTRUE;
479 
480 	result := dbms_lock.request (hndl, 6, 0);  -- ULX lock
481 
482 	if (result in (0, 4)) then	-- Success or own lock
483 	  status := NTRUE;
484 	elsif (result in (1, 2)) then	-- Timeout or deadlock
485 	  status := NFALSE;
486 	else				-- Bad lock handle or bad param
487 	  e_code := NFALSE;
488 	end if;
489 
490 	exception
491 	  when others then
492 	    e_code := NFALSE;
493 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
494 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
495 	    fnd_message.set_token ('ROUTINE', 'REQUEST_LOCK (hndl)', FALSE);
496   end request_lock;
497 
498 
499   procedure release_lock (hndl	 in     varchar2,
500 			  e_code in out nocopy number) is
501 
502 	result	number;
503 
504   begin
505 	result := dbms_lock.release (hndl);
506 
507 	if ((result = 0) or (result = 4)) then
508 	  e_code := NTRUE;
509 	else
510 	  e_code := NFALSE;
511 	end if;
512 
513 	exception
514 	  when others then
515 	    e_code := NFALSE;
516 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
517 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
518 	    fnd_message.set_token ('ROUTINE', 'release_lock', FALSE);
519   end release_lock;
520 
521 
522   procedure clean_mgrs (e_code in out nocopy number) is
523 
524   begin
525 	null;
526   end clean_mgrs;
527 
528 
529   procedure monitor_icm (hndl   in out nocopy varchar2,
530 			 up	in out nocopy number,
531 			 logf	in out nocopy varchar2,
532 			 node	in out nocopy varchar2,
533 			 inst	in out nocopy varchar2,
534 			 cpid	in out nocopy number,
535 			 mthd	in     number,	-- PMON method
536 			 e_code in out nocopy number) is
537 
538 	lk		varchar2(50);
539 	result		number;
540 	bad_lock	exception;
541 	time_interval	number;			-- PMON method = TSTAMP
542 	time_difference	number;			-- PMON method = TSTAMP
543 	dummy		number;
544 
545   begin
546 	e_code := NTRUE;
547 
548 	if (mthd = TSTAMP) then			-- PMON method = TSTAMP
549 	  cpid := get_pid_time (time_interval,
550 				time_difference,
551 				0, 1, 'A', 'C', 'M', 'K');
552 
553 	  if (time_difference < THRSHLD * time_interval) then
554 	    up := NTRUE;
555 	    rollback;
556 	    return;
557 	  end if;
558 
559 	else					-- PMON method = DBLOCK
560 	  cpid := get_icm_info (logf, node, inst);
561 
562 	  if (hndl is not null) then
563 	    result := dbms_lock.request (hndl, 6, 0);  -- ULX lock
564 
565             if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
566               fnd_log.string(FND_LOG.LEVEL_EVENT,
567                   'fnd.plsql.FND_DCP.MONITOR_ICM',
568                   'lock request result='||to_char(result)||' for hndl='||hndl);
569             end if;
570 
571 
572 	    if (result in (1, 2)) then	-- Timeout or deadlock
573 	      up := NTRUE;
574 	      return;
575 	    end if;
576 
577 	  end if;
578 
579 	end if;					-- PMON method TSTAMP/DBLOCK
580 
581 	if (cpid is null) then
582           if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
583             fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.MONITOR_ICM',
584                     'get_icm_info returned cpid NULL');
585           end if;
586 
587 	  up := NTRUE;
588 	  hndl := null;
589           rollback;
590 	  return;
591 
592 	else
593           if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
594             fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.MONITOR_ICM',
595                     'get_icm_info returned cpid='||to_char(cpid));
596           end if;
597 
598 	  lk := FNDCPLK || '0_1_' || cpid;
599 	  dbms_lock.allocate_unique (lk, hndl, EON);
600 	  result := dbms_lock.request (hndl, 6, 0);  -- ULX lock
601 
602           if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
603             fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.MONITOR_ICM',
604                   'new lock name = '||lk);
605             fnd_log.string(FND_LOG.LEVEL_EVENT, 'fnd.plsql.FND_DCP.MONITOR_ICM',
606                   'lock request result='||to_char(result)||' for hndl='||hndl);
607           end if;
608 
609 	  if (result = 0) then		-- Success
610 	    select 1 into dummy
611             from fnd_concurrent_processes
612 	    where concurrent_process_id = cpid
613 	    for update nowait;
614 
615 	    update fnd_concurrent_processes
616 	       set process_status_code = decode (process_status_code,
617 						 'A', 'K',
618 						 'M', 'S',
619 						       process_status_code)
620 	     where concurrent_process_id = cpid;
621 	    up := NFALSE;
622 	    commit;
623 	  elsif (result in (1, 2)) then	-- Timeout or deadlock
624 	    up := NTRUE;
625 	  elsif (result = 4) then	-- Own the lock (shouldn't happen)
626 	    up := NFALSE;
627 	  else				-- Bad lock handle or bad param
628 	    raise bad_lock;
629 	  end if;
630 
631 	end if;
632 
633 	exception
634 	  when others then
635 	    e_code := NFALSE;
636 	    rollback;
637 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
638 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
639 	    fnd_message.set_token ('ROUTINE', 'monitor_icm', FALSE);
640   end monitor_icm;
641 
642 
643   procedure monitor_im (apid   in     number,
644 			qid    in     number,
645 			pid    in     number,
646 			cnode  in     varchar2,
647 			status in out nocopy number,
648 			e_code in out nocopy number) is
649 
650 	max_procs	number;
651 	run_procs	number;
652 	ccode		varchar2(1);	-- Control code
653 	tnode		varchar2(30);	-- Target node
654 
655   begin
656 	e_code := NTRUE;
657 
658 	select max_processes,
659 	       running_processes,
660 	       control_code,
661 	       target_node
662 	  into max_procs,
663 	       run_procs,
664 	       ccode,
665 	       tnode
666 	  from fnd_concurrent_queues
667 	 where application_id = apid
668 	   and concurrent_queue_id = qid;
669 
670 	if ((max_procs < run_procs) or
671 	    (cnode <> tnode)) then	-- Migrate
672 	  status := NFALSE;			-- Exit
673 	else
674 	  status := NTRUE;			-- Stay up
675 	end if;
676 
677 	exception
678 	  when others then
679 	    e_code := NFALSE;
680 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
681 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
682 	    fnd_message.set_token ('ROUTINE', 'monitor_im', FALSE);
683   end monitor_im;
684 
685 
686   procedure reassign_lkh (e_code in out nocopy number) is
687 
688 	cursor 	c1 is
689 		   select queue_application_id,
690 			  concurrent_queue_id,
691 			  concurrent_process_id,
692 			  rowid
693 		     from fnd_concurrent_processes
694 		    where manager_type between 1 and 5
695 		      and process_status_code in ('A', 'C')
696 		 order by concurrent_process_id;
697 
698 	apid	number(15);
699 	qid	number(15);
700 	pid	number(15);
701 	rid	ROWID;
702 	hndl	varchar2(128);
703 
704   begin
705 	e_code := NTRUE;
706 
707 	open c1;
708 
709 	loop
710 	  fetch c1 into apid, qid, pid, rid;
711 	  exit when c1%notfound;
712 
713 	  dbms_lock.allocate_unique (FNDCPLK ||
714 				     apid || '_' || qid || '_' || pid,
715 				     hndl, EON);
716 
717 	  update fnd_concurrent_processes
718 	     set lk_handle = hndl
719 	   where rowid = rid;
720 
721 	end loop;
722 
723 	close c1;
724 	commit;
725 
726 	exception
727 	  when others then
728 	    e_code := NFALSE;
729 	    fnd_message.set_name ('FND', 'CP-Generic oracle error');
730 	    fnd_message.set_token ('ERROR', substr (sqlerrm, 1, 30), FALSE);
731 	    fnd_message.set_token ('ROUTINE', 'reassign_lkh', FALSE);
732   end reassign_lkh;
733 
734 
735   /* function get_inst_num
736    *
737    * This function is used to determine the OPS instance
738    * to which a manager should "specialize".  For Parallel
739    * Concurrent Processing, we want the a manager to
740    * service requests only for the instance associated with
744    * the current instance number is retrieved from v$instance,
741    * its primary node.
742    *
743    * If the manager was started on its primary node, then
745    * stored in fnd_concurrent_queues, and returned to the caller.
746    *
747    * If the manager was started on its secondary node, then
748    * the instance number is retrieved from fnd_concurrent_queues
749    *
750    * Parameters:
751    *   queue_appl_id - Concurrent queue application ID.
752    *   queue_id      - Concurrent queue ID.
753    *   current_node  - Node where manager is running.
754    *
755    * Returns:
756    *   An OPS instance number.
757    *
758    * Alters:
759    *   The table fnd_concurrent_queues may be updated.
760    *
761    * Assumptions:
762    *   This function assumes that the node names stored in
763    *   fnd_concurrent_queues exactly match those in the manager's
764    *   sysinfo structure.  (i.e. Both fully qualified, or both not
765    *   fully qualified)
766    *
767    * Error conditions:
768    *
769    *   All other exceptions are unhandled.
770    */
771 
772   function get_inst_num	(queue_appl_id	in	number,
773 			 queue_id	in	number,
774 			 current_node	in	varchar2)
775 			return number is
776     primary_node   fnd_concurrent_queues.node_name%type;
777     secondary_node fnd_concurrent_queues.node_name2%type;
778     inst_num number; /* OPS Instance Number */
779   begin
780     /* Are we on the primary node?*/
781     select upper(node_name), upper(node_name2)
782       into primary_node, secondary_node
783       from fnd_concurrent_queues
784       where concurrent_queue_id = queue_id
785         and application_id = queue_appl_id;
786 
787 
788     if (upper(current_node) = primary_node) then /* PCP Primary node */
789       /* Get inst number from v$instance */
790       select instance_number
791         into inst_num
792         from v$instance;
793 
794       /* Store it into fnd_concurrent_queues. */
795 
796       update fnd_concurrent_queues
797 		set instance_number = inst_num
798 		where application_id = queue_appl_id
799 		and concurrent_queue_id = queue_id;
800 
801       /* Update the global */
802       FND_CONC_GLOBAL.Override_OPS_INST_NUM(inst_num);
803 
804     else /* we aren't on the primary node...maybe we still know the inst num*/
805       select INSTANCE_NUMBER
806       into inst_num
807       from fnd_concurrent_queues
808       where application_id = queue_appl_id
809       and concurrent_queue_id = queue_id;
810 
811       /* Update the global...if not null */
812       if (inst_num is not null) then
813 	  FND_CONC_GLOBAL.Override_OPS_INST_NUM(inst_num);
814       end if;
815     end if;
816 
817     return inst_num;
818   end;
819 
820   /* function target_node_mgr_chk
821    * If a request is targeted to a specific node, the concurrent
822    * manager will use this function in his request query (afpgrq)
823    * to filter it out if it doesn't meet any of the following conditions:
824    * a) request's target node is the same as manager's current node
825    * b)	request's target node is different from manager's current node, but the
826    *    FND_NODES status is 'N' or node_mode is not 'O' (online).
827    * c)	There are no managers specialized to run this request on request's
828    *    target node
829    *
830    * Parameters:
831    *   request_id - id of request that is targeted to a secific node
832    *
833    * Returns:
834    *   NTRUE/TRUE/1   if this request can appear in query results
835    *   NFALSE/FALSE/0 if this request should be filtered from query results
836    *
837    * Assumptions:
838    *   The manager's target_node in fnd_concurrent_queues is it's current
839    *   node.  This should always be true for active managers in afpgrq.
840    *
841    * Error conditions:
842    *
843    *   All other exceptions are unhandled.
844    */
845 
846    function target_node_mgr_chk (req_id  in number) return number is
847 
848       cursor mgr_cursor (rid number, qappid number, qid number) is
849         select queue_application_id, concurrent_queue_id,
850              running_processes, max_processes,
851              decode(control_code,
852                     'T','N',       -- Abort
853                     'X','N',       -- Aborted
854                     'D','N',       -- Deactivate
855                     'E','N',       -- Deactivated
856                         'Y') active,
857              target_node
858           from fnd_concurrent_worker_requests
859           where request_id = rid
860             and not((queue_application_id = 0)
861                   and (concurrent_queue_id in (1,4)))
862             and not((queue_application_id = qappid)
863                   and (concurrent_queue_id = qid ));
864 
865       my_q_appl_id    number := FND_GLOBAL.queue_appl_id ;
866       my_q_id         number := FND_GLOBAL.conc_queue_id;
867       req_node        varchar2(30) := null;
868       dummy           number := 0;
869       retval          number := NFALSE;
870 
871    begin
872 
873       if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
874           fnd_log.string(FND_LOG.LEVEL_STATEMENT,
875                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
879       end if;
876                'Enter TARGET_NODE_MGR_CHK for manager ('||
877                to_char(my_q_appl_id)|| '/'||my_q_id||
878                ') and request_id '|| to_char(req_id));
880 
881       /* Retrieve the request's target node */
882       select node_name1
883         into req_node
884         from fnd_concurrent_requests
885        where request_id = req_id;
886 
887       if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
888           fnd_log.string(FND_LOG.LEVEL_STATEMENT,
889                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
890                'Target node for request '||to_char(req_id)||' is '||
891                NVL(req_node,'NULL'));
892       end if;
893 
894       /* If request has no target node, okay to run it */
895       if (req_node is null) then
896          retval := NTRUE;
897       end if;
898 
899       /* Check if the request node matches my node */
900       if (retval = NFALSE) then
901         if (my_node is NULL) then
902           select target_node
903             into my_node
904             from fnd_concurrent_queues
905            where application_id = my_q_appl_id
906              and concurrent_queue_id = my_q_id;
907         end if;
908 
909         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
910             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
911                  'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
912                  'Manager node is '||NVL(my_node,'NULL'));
913         end if;
914 
915         /* If request target node matches my node, okay to run it */
916         if (req_node = my_node) then
917            retval := NTRUE;
918         end if;
919       end if;
920 
921       /* Check if the request node is down */
922       if (retval = NFALSE) then
923         select count(*)
924           into dummy
925           from fnd_nodes
926          where node_name = req_node
927            and (node_mode <> 'O'
928             or status <> 'Y');
929 
930         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
931           if dummy >= 1 then
932             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
933                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
934                'Request target node '||req_node||' is DOWN');
935           else
936             fnd_log.string(FND_LOG.LEVEL_STATEMENT,
937                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
938                'Request target node '||req_node||' is UP');
939           end if;
940         end if;
941 
942          /* If request target node is down, okay to run it */
943          if (dummy >= 1) then
944             retval := NTRUE;
945 	    fnd_message.set_name ('FND', 'CONC-REQ NODE NOT HONORED');
946 	    fnd_message.set_token ('REQID', to_char(req_id), FALSE);
947 	    fnd_message.set_token ('NODE', req_node, FALSE);
948             if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
949               fnd_log.message(FND_LOG.LEVEL_EVENT,
950                               'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
951                               FALSE);
952             end if;
953          end if;
954       end if;
955 
956       /* Check if a manager is available to run this request on target node */
957       /* The first available manager we find, exit and return NFALSE        */
958       if (retval = NFALSE) then
959         if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
960            fnd_log.string(FND_LOG.LEVEL_STATEMENT,
961               'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
962               'Enter loop to determine if another manager can run');
963         end if;
964         for mgr_rec in mgr_cursor(req_id, my_q_appl_id, my_q_id) loop
965           if ((mgr_rec.active = 'Y')
966               and (mgr_rec.max_processes > 0)
967               and (mgr_rec.running_processes > 0)
968               and mgr_rec.target_node = req_node) then
969                  /* Here is an available manager, no need to continue. */
970                  if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
971                      fnd_log.string(FND_LOG.LEVEL_STATEMENT,
972                           'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
973                           'Another manager ('||
974                            to_char(mgr_rec.queue_application_id )||'/'||
975                            to_char(mgr_rec.concurrent_queue_id)||
976                           ') can run this request');
977                  end if;
978                  retval := NFALSE;
979                  exit;
980           else
981               retval := NTRUE;
982 	      fnd_message.set_name ('FND', 'CONC-REQ NODE NOT HONORED');
983 	      fnd_message.set_token ('REQID', to_char(req_id), FALSE);
984 	      fnd_message.set_token ('NODE', req_node, FALSE);
985               if( FND_LOG.LEVEL_EVENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
986                 fnd_log.message(FND_LOG.LEVEL_EVENT,
987                                 'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
988                                 FALSE);
989               end if;
990           end if;
991         end loop;
992       end if;
993 
994       if( FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL ) then
995        if retval = NTRUE then
996          fnd_log.string(FND_LOG.LEVEL_STATEMENT,
997                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
998                'Returning retval= NTRUE');
999        else
1000          fnd_log.string(FND_LOG.LEVEL_STATEMENT,
1001                'fnd.plsql.FND_DCP.TARGET_NODE_MGR_CHK',
1002                'Returning retval= NFALSE');
1003        end if;
1004       end if;
1005       return retval;
1006 
1007    end target_node_mgr_chk;
1008 
1009   --
1010   -- Name
1011   --   is_dcp
1012   -- Purpose
1013   --   Returns TRUE if the environment has multiple CP nodes,
1014   --   FALSE if not.
1015   --
1016   -- Parameters:
1017   -- None
1018   --
1019   -- Returns:
1020   --   NTRUE/TRUE/1   - environment is DCP
1021   --   NFALSE/FALSE/0 - environment is non-DCP
1022   --
1023   function is_dcp return number is
1024 
1025     node_count number := 0;
1026   begin
1027 
1028     select count(*)
1029       into node_count
1030       from fnd_nodes
1031      where node_name <> 'AUTHENTICATION'
1032        and support_cp = 'Y';
1033 
1034     if (node_count > 1) then
1035       return NTRUE;
1036     else
1037       return NFALSE;
1038     end if;
1039 
1040   end is_dcp;
1041 
1042 
1043 end FND_DCP;