DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_UMS_ANALYSIS_ENGINE

Source


1 package body fnd_ums_analysis_engine as
2 /* $Header: AFUMSAEB.pls 120.1 2005/07/02 04:20:36 appldev noship $ */
3 
4 -- define the newline character
5 
6 NEWLINE varchar2(3);
7 
8 -- initial engine mode
9 
10 MODE_NOT_CALLED                constant varchar2(30) := 'ENGINE_NOT_CALLED';
11 
12 -- Global APPL_TOP Id. Should be replaced with AD_PATCH.GLOBAL_APPL_TOP_ID
13 
14 GLOBAL_APPL_TOP_ID             constant number := -1;
15 
16 -- bugfix release statuses:
17 
18 RSTATUS_IN_PROGRESS            constant varchar2(30) := 'IN_PROGRESS';
19 RSTATUS_RELEASED               constant varchar2(30) := 'RELEASED';
20 RSTATUS_RELEASED_HIGH_PRIORITY constant varchar2(30) := 'RELEASED_HIGH_PRIORITY';
21 RSTATUS_SUPERSEDED             constant varchar2(30) := 'SUPERSEDED';
22 RSTATUS_OBSOLETED              constant varchar2(30) := 'OBSOLETED';
23 
24 -- patch types:
25 
26 -- US patch with UMS metadata
27 
28 PATCH_TYPE_US_UMS              constant varchar2(30) := 'US_UMS';
29 
30 -- US patch without UMS metadata
31 
32 PATCH_TYPE_US_NON_UMS          constant varchar2(30) := 'US_NON_UMS';
33 
34 -- NLS patch (no UMS metadata)
35 -- Implicitly prereqs the US patch of the same bug number.
36 
37 PATCH_TYPE_NLS_PATCH           constant varchar2(30) := 'NLS_PATCH';
38 
39 -- NLS bugfix (no UMS metadata)
40 -- NLS bugfix is a fix for translation bug. There is no US patch for
41 -- the same bug number. Language code is prefixed with 'NLS_'.
42 
43 PATCH_TYPE_NLS_BUGFIX          constant varchar2(30) := 'NLS_BUGFIX';
44 
45 -- replacement types:
46 -- see get_replacement_bugfix_guid() for more details.
47 
48 REPLACEMENT_ORIGINAL           constant varchar2(30) := 'ORIGINAL_REPLACEMENT';
49 REPLACEMENT_FIRST_NON_OBSOLETE constant varchar2(30) := 'FIRST_NON_OBSOLETE_REPLACEMENT';
50 REPLACEMENT_LAST_NON_OBSOLETE  constant varchar2(30) := 'LAST_NON_OBSOLETE_REPLACEMENT';
51 
52 -- bugfix application statuses:
53 
54 -- bugfix has not been applied
55 
56 APP_STATUS_NOT_APPLIED         constant varchar2(30) := 'NOT_APPLIED';
57 
58 -- bugfix is implicitly applied; all its files and all its prereqs
59 -- (or their equivalent) are applied
60 
61 APP_STATUS_IMPLICITLY_APPLIED  constant varchar2(30) := 'IMPLICITLY_APPLIED';
62 
63 -- bugfix has been explicitly applied
64 
65 APP_STATUS_EXPLICITLY_APPLIED  constant varchar2(30) := 'EXPLICITLY_APPLIED';
66 
67 -- bugfix has been effectively applied
68 
69 APP_STATUS_EFFECTIVELY_APPLIED constant varchar2(30) := 'EFFECTIVELY_APPLIED';
70 
71 -- Equivalency Results for Post Processing Algorithm
72 
73 EQUIVALENCY_TERMINATED         constant varchar2(30) := 'EQUIVALENCY_TERMINATED';
74 EQUIVALENCY_IN_PROGRESS        constant varchar2(30) := 'EQUIVALENCY_IN_PROGRESS';
75 EQUIVALENCY_COMPLETED_NONE     constant varchar2(30) := 'EQUIVALENCY_COMPLETED_NONE';
76 EQUIVALENCY_COMPLETED_REQUIRED constant varchar2(30) := 'EQUIVALENCY_COMPLETED_REQUIRED';
77 EQUIVALENCY_COMPLETED_MERGED   constant varchar2(30) := 'EQUIVALENCY_COMPLETED_MERGED';
78 EQUIVALENCY_COMPLETED_APPLIED  constant varchar2(30) := 'EQUIVALENCY_COMPLETED_APPLIED';
79 
80 -- maximum number of calls to get_equivalency_result() function
81 
82 MAX_GET_EQUIVALENCY_CALL_COUNT constant number := 5000;
83 
84 -- Report symbols
85 
86 SYMBOL_OBSOLETED               constant varchar2(10) := '*';
87 SYMBOL_MISSING                 constant varchar2(10) := '!';
88 SYMBOL_APPLIED                 constant varchar2(10) := '+';
89 SYMBOL_NO_INFORMATION          constant varchar2(10) := '?';
90 SYMBOL_NOT_APPLIED             constant varchar2(10) := '-';
91 
92 -- raise_application_error codes
93 
94 ERROR_AD_IS_PATCH_APPLIED      constant number := -20001;
95 ERROR_AD_IS_FILE_COPIED        constant number := -20002;
96 ERROR_AD_SET_PATCH_STATUS      constant number := -20003;
97 
98 ERROR_UMS_OTHERS               constant number := -20100;
99 ERROR_UMS_REPLACEMENT_TYPE     constant number := -20101;
100 ERROR_UMS_PATCH_TYPE           constant number := -20104;
101 ERROR_UMS_ARRAY_NAME           constant number := -20105;
102 ERROR_UMS_ENGINE_NOT_CALLED    constant number := -20107;
103 ERROR_UMS_ILLEGAL_STATE        constant number := -20108;
104 ERROR_UMS_MISSING_DATA         constant number := -20111;
105 ERROR_UMS_INVALID_ENGINE_MODE  constant number := -20113;
106 ERROR_UMS_INVALID_BUG_LIST     constant number := -20114;
107 ERROR_UMS_INVALID_APPL_TOP_ID  constant number := -20115;
108 
109 -- the maximum size of a piece of the report
110 
111 MAX_REPORT_SIZE                constant number := 32000;
112 
113 -- Generic use array types
114 
115 type BINARY_INTEGER_ARRAY      is table of binary_integer index by binary_integer;
116 type VARCHAR2_ARRAY            is table of varchar2(32000) index by binary_integer;
117 
118 -- Arrays for bulk fetching
119 
120 type BUGFIX_GUID_ARRAY         is table of fnd_ums_bugfixes.bugfix_guid%TYPE index by binary_integer;
121 type RELATION_TYPE_ARRAY       is table of fnd_ums_bugfix_relationships.relation_type%TYPE index by binary_integer;
122 
123 -- a bugfix in the dependency graph
124 
125 type bugfix is record
126     (-- primary key
127      bugfix_index                   binary_integer,
128 
129      -- attributes from FND_UMS_BUGFIXES
130      bugfix_guid                    fnd_ums_bugfixes.bugfix_guid%type,
131      release_name                   fnd_ums_bugfixes.release_name%type,
132      bug_number                     fnd_ums_bugfixes.bug_number%type,
133      download_mode                  fnd_ums_bugfixes.download_mode%type,
134      application_short_name         fnd_ums_bugfixes.application_short_name%type,
135      release_status                 fnd_ums_bugfixes.release_status%type,
136      type                           fnd_ums_bugfixes.type%type,
137      abstract                       fnd_ums_bugfixes.abstract%type,
138 
139      -- attributes passed in
140      language_code                  varchar2(30),
141 
142      -- derived attributes
143      patch_type                     varchar2(30),
144      ad_application_status          varchar2(30),
145      bugfix_id                      varchar2(60),
146      merged                         boolean,
147 
148      -- attributes used during prereq check
149      replacement_chain_tag          number,
150      application_status             varchar2(30),
151      required                       boolean,
152 
153      -- post processing equivalency properties,
154      equivalency_result             varchar2(30),
155      equivalency_path               varchar2(32000),
156      equivalent_bugfix_index        binary_integer);
157 
158 type BUGFIX_ARRAY              is table of bugfix index by binary_integer;
159 
160 -- Input passed to Analysis Engine.
161 
162 type input_bug is record
163     (bug_number                     number,
164      language_code                  varchar2(30));
165 
166 type INPUT_BUG_ARRAY           is table of input_bug index by binary_integer;
167 
168 type replacement_chain is record
169     (bugfix_count                   number,
170      bugfix_indexes                 binary_integer_array);
171 
172 type globals_record is record
173     (-- the one-based array of report pieces
174      report_count                   number,
175      report                         VARCHAR2_ARRAY,
176 
177      -- the number of top-level bugfixes
178      top_level_bugfix_count         number,
179      top_level_bugfix_indexes       BINARY_INTEGER_ARRAY,
180 
181      -- obsolete top-level bugfix exists flag
182      obs_top_level_bugfix_exists    boolean,
183 
184      -- the number of bugfixes
185      bugfix_count                   number,
186 
187      -- the required bugfixes
188      required_bugfix_count          number,
189      required_bugfix_indexes        BINARY_INTEGER_ARRAY,
190 
191      -- the prereq list
192      prereq_list                    varchar2(32000),
193 
194      -- the depth of the recursion used for indenting the debug output
195      indent_level                   number,
196 
197      -- the mode
198      engine_mode                    varchar2(30),
199 
200      -- the root cause error message
201      root_cause_error_message       varchar2(32000),
202 
203      -- the unhandled exception depth
204      exception_depth                number,
205 
206      -- the APPL_TOP id
207      appl_top_id                    number,
208 
209      -- the debug flag
210      debug_on                       boolean,
211 
212      -- replacement chain cycle detection counter
213      replacement_chain_tag_counter  number,
214 
215      -- number of calls to get_equivalency_result() function
216      get_equivalency_call_count     number,
217 
218      -- engine return status
219      status                         varchar2(30));
220 
221 -- Global Variables
222 
223 g_globals           globals_record;
224 
225 g_bugfixes          BUGFIX_ARRAY;
226 
227 g_arcs_revision     varchar2(32000);
228 
229 --------------------------------------------------------------------------------
230 -- Returns TRUE iff analyze_dependencies (engine) is called.
231 --
232 -- return: TRUE iff analyze_dependencies (engine) is called; FALSE otherwise.
233 --------------------------------------------------------------------------------
234 function is_engine_called
235    return boolean
236 is
237    l_return boolean;
238 begin
239    if (g_globals.engine_mode = MODE_NOT_CALLED) then
240       l_return := false;
241    else
242       l_return := true;
243    end if;
244 
245    return l_return;
246 end is_engine_called;
247 
248 --------------------------------------------------------------------------------
249 -- Gets the relation type as text.
250 --
251 -- p_relation_type - the relation type
252 --
253 -- return: the relation type as text
254 --------------------------------------------------------------------------------
255 function get_relation_type_as_text(p_relation_type in varchar2)
256    return varchar2
257 is
258    l_text varchar2(30);
259 begin
260    if (p_relation_type = fnd_ums_loader.REL_TYPE_PREREQS) then
261       l_text := 'Prereqs';
262    elsif (p_relation_type = fnd_ums_loader.REL_TYPE_INDIRECTLY_PREREQS) then
263       l_text := 'Indirectly Prereqs';
264    elsif (p_relation_type = fnd_ums_loader.REL_TYPE_INCLUDES) then
265       l_text := 'Includes';
266    elsif (p_relation_type = fnd_ums_loader.REL_TYPE_INDIRECTLY_INCLUDES) then
267       l_text := 'Indirectly Includes';
268    elsif (p_relation_type = fnd_ums_loader.REL_TYPE_REPLACED_BY) then
269       l_text := 'Replaced by';
270    else
271       l_text := p_relation_type;
272    end if;
273 
274    return l_text;
275 end get_relation_type_as_text;
276 
277 --------------------------------------------------------------------------------
278 -- Appends a line to the report.
279 --
280 -- p_text - the text to append to the report
281 --------------------------------------------------------------------------------
282 procedure append_to_report(p_text in varchar2)
283 is
284 begin
285    if (lengthb(g_globals.report(g_globals.report_count)) +
286        lengthb(p_text) + lengthb(NEWLINE) > MAX_REPORT_SIZE) then
287       -- appending the text to the current piece of the report would exceed its
288       -- maximum allowed size so initialize the next piece of the report
289 
290       g_globals.report_count := g_globals.report_count + 1;
291       g_globals.report(g_globals.report_count) := '';
292    end if;
293 
294    g_globals.report(g_globals.report_count) := g_globals.report(g_globals.report_count) ||
295       rtrim(p_text, NEWLINE) || NEWLINE;
296 end append_to_report;
297 
298 --------------------------------------------------------------------------------
299 -- Logs a message to the global report if in DEBUG mode.  Indents the line
300 -- according to the value of g_globals.indent_level.
301 --
302 -- p_text - the text to log
303 --------------------------------------------------------------------------------
304 procedure debug_to_report(p_text in varchar2)
305 is
306    l_text varchar2(2000);
307 begin
308    if (g_globals.debug_on) then
309       -- indent the line according to indent_level
310 
311       l_text := lpad(p_text, length(p_text) + 3*g_globals.indent_level);
312 
313       append_to_report(l_text);
314    end if;
315 exception
316    when others then
317       null;
318 end debug_to_report;
319 
320 --------------------------------------------------------------------------------
321 -- Logs unhandled exception info to the report.
322 --
323 -- p_method - name of the method reporting exception
324 --------------------------------------------------------------------------------
325 procedure exception_to_report
326 is
327 begin
328    append_to_report(' ');
329    append_to_report(rpad('=', 80, '='));
330 
331    -- Root cause of the problem
332    append_to_report(g_globals.root_cause_error_message);
333 
334    append_to_report(' ');
335    append_to_report('----- Error Message Stack -----');
336    append_to_report(dbms_utility.format_error_stack());
337 
338    if (g_globals.debug_on) then
339       append_to_report(' ');
340       append_to_report(dbms_utility.format_call_stack());
341    end if;
342 
343    append_to_report(rpad('=', 80, '='));
344 exception
345    when others then
346       null;
347 end exception_to_report;
348 
349 --------------------------------------------------------------------------------
350 -- Converts boolean to char.
351 --
352 -- p_boolean - boolean variable
353 --
354 -- return: Char representation of boolean variable.
355 --------------------------------------------------------------------------------
356 function boolean_to_char(p_boolean in boolean)
357    return varchar2
358 is
359    l_return varchar2(100);
360 begin
361    if (p_boolean is null) then
362       l_return := 'NULL';
363    elsif (p_boolean) then
364       l_return := 'TRUE';
365    else
366       l_return := 'FALSE';
367    end if;
368 
369    return l_return;
370 
371 end boolean_to_char;
372 
373 --------------------------------------------------------------------------------
374 -- Returns formatted method call
375 --
376 -- p_method - name of the method
377 -- p_arg1..5 - method arguments
378 --
379 -- return: formatted method call
380 --------------------------------------------------------------------------------
381 function get_formatted_method_call(p_method in varchar2,
382                                    p_arg1   in varchar2 default null,
383                                    p_arg2   in varchar2 default null,
384                                    p_arg3   in varchar2 default null,
385                                    p_arg4   in varchar2 default null,
386                                    p_arg5   in varchar2 default null)
387    return varchar2
388 is
389    l_method varchar2(32000);
390 begin
391    l_method := p_method || '(';
392 
393    if (p_arg1 is not null) then
394       l_method := l_method || p_arg1;
395    end if;
396 
397    if (p_arg2 is not null) then
398       l_method := l_method || ', ' || p_arg2;
399    end if;
400 
401    if (p_arg3 is not null) then
402       l_method := l_method || ', ' || p_arg3;
403    end if;
404 
405    if (p_arg4 is not null) then
406       l_method := l_method || ', ' || p_arg4;
407    end if;
408 
409    if (p_arg5 is not null) then
410       l_method := l_method || ', ' || p_arg5;
411    end if;
415    return l_method;
412 
413    l_method := l_method || ')';
414 
416 
417 exception
418    when others then
419       return p_method;
420 end get_formatted_method_call;
421 
422 --------------------------------------------------------------------------------
423 -- Returns formatted error.
424 --
425 -- p_line0 - The first line that goes after ORA error number
426 -- p_line1..5 - optional lines to be indented
427 --
428 -- return: formatted error message
429 --------------------------------------------------------------------------------
430 function get_formatted_error(p_line0 in varchar2,
431                              p_line1 in varchar2 default null,
432                              p_line2 in varchar2 default null,
433                              p_line3 in varchar2 default null,
434                              p_line4 in varchar2 default null,
435                              p_line5 in varchar2 default null)
436    return varchar2
437 is
438    l_error_text     varchar2(32000);
439    l_newline_indent varchar2(2000);
440 begin
441    --
442    -- 12345678901
443    -- ORA-xxxxx: <p_line0>
444    --            <p_line1>
445    --            <p_line2>
446    --
447 
448    l_newline_indent := NEWLINE || rpad(' ', 11, ' ');
449 
450    l_error_text := p_line0;
451 
452    if (p_line1 is not null) then
453       l_error_text := l_error_text || l_newline_indent || p_line1;
454    end if;
455 
456    if (p_line2 is not null) then
457       l_error_text := l_error_text || l_newline_indent || p_line2;
458    end if;
459 
460    if (p_line3 is not null) then
461       l_error_text := l_error_text || l_newline_indent || p_line3;
462    end if;
463 
464    if (p_line4 is not null) then
465       l_error_text := l_error_text || l_newline_indent || p_line4;
466    end if;
467 
468    if (p_line5 is not null) then
469       l_error_text := l_error_text || l_newline_indent || p_line5;
470    end if;
471 
472    return l_error_text;
473 
474 end get_formatted_error;
475 
476 --------------------------------------------------------------------------------
477 -- Raises formatted application error.
478 --
479 -- p_error_code - error code
480 -- p_error_text - error text
481 --------------------------------------------------------------------------------
482 procedure raise_formatted_error(p_error_code in number,
483                                 p_error_text in varchar2)
484 is
485    l_error_text varchar2(32000);
486 begin
487    l_error_text := p_error_text || NEWLINE || dbms_utility.format_error_stack();
488 
489    raise_application_error(p_error_code, l_error_text);
490 
491 exception
492    when others then
493       --
494       -- Store the root cause of the problem. This will be presented to
495       -- user as the main cause of the exception. Rest of the exception is
496       -- basically the call stack trace.
497       --
498       if (g_globals.exception_depth = 0) then
499          g_globals.root_cause_error_message := dbms_utility.format_error_stack();
500       end if;
501 
502       g_globals.exception_depth := g_globals.exception_depth + 1;
503 
504       if (g_globals.debug_on) then
505          exception_to_report();
506       end if;
507 
508       raise;
509 end raise_formatted_error;
510 
511 --------------------------------------------------------------------------------
512 -- Raises formatted error for 'when others then' block
513 --
514 -- p_method - name of the method
515 -- p_arg1..5 - method arguments
516 --------------------------------------------------------------------------------
517 procedure raise_others_error(p_method in varchar2,
518                              p_arg1   in varchar2 default null,
519                              p_arg2   in varchar2 default null,
520                              p_arg3   in varchar2 default null,
521                              p_arg4   in varchar2 default null,
522                              p_arg5   in varchar2 default null)
523 is
524    l_error_text varchar2(32000);
525 begin
526    l_error_text := get_formatted_method_call(p_method,
527                                              p_arg1,
528                                              p_arg2,
529                                              p_arg3,
530                                              p_arg4,
531                                              p_arg5);
532 
533    l_error_text := l_error_text || ' raised exception.';
534 
535    raise_formatted_error(ERROR_UMS_OTHERS, l_error_text);
536 
537    -- No exception handling here
538 end raise_others_error;
539 
540 --------------------------------------------------------------------------------
541 -- Sorts required bugfixes
542 --------------------------------------------------------------------------------
543 procedure sort_required_bugfixes
544 is
545    l_tmp_index      binary_integer;
546    l_min_index      binary_integer;
547    l_min_bug_number number;
548 begin
549    -- use selection sort algorithm
550 
551    for i in 0 .. g_globals.required_bugfix_count - 1 loop
552       l_min_index := i;
556 
553       l_min_bug_number := g_bugfixes(g_globals.required_bugfix_indexes(i)).bug_number;
554 
555       for j in i + 1 .. g_globals.required_bugfix_count - 1 loop
557          if (g_bugfixes(g_globals.required_bugfix_indexes(j)).bug_number < l_min_bug_number) then
558             l_min_index := j;
559             l_min_bug_number := g_bugfixes(g_globals.required_bugfix_indexes(j)).bug_number;
560          end if;
561 
562       end loop;
563 
564       if (l_min_index <> i) then
565          l_tmp_index := g_globals.required_bugfix_indexes(i);
566          g_globals.required_bugfix_indexes(i) := g_globals.required_bugfix_indexes(l_min_index);
567          g_globals.required_bugfix_indexes(l_min_index) := l_tmp_index;
568       end if;
569    end loop;
570 
571 exception
572    when others then
573       raise_others_error('sort_required_bugfixes');
574 end sort_required_bugfixes;
575 
576 --------------------------------------------------------------------------------
577 -- Generates a comma seperated list of required bugfixes.
578 --------------------------------------------------------------------------------
579 function compute_prereq_list
580    return varchar2
581 is
582    l_prereq_list varchar2(32000);
583 begin
584    l_prereq_list := '';
585 
586    -- sort required bugfixes
587 
588    sort_required_bugfixes();
589 
590    for i in 0 .. g_globals.required_bugfix_count - 1 loop
591 
592       if (i > 0) then
593          l_prereq_list := l_prereq_list || ',';
594       end if;
595 
596       l_prereq_list := l_prereq_list || g_bugfixes(g_globals.required_bugfix_indexes(i)).bug_number;
597    end loop;
598 
599    return l_prereq_list;
600 
601 exception
602    when others then
603       raise_others_error('compute_prereq_list');
604 end compute_prereq_list;
605 
606 --------------------------------------------------------------------------------
607 -- Prints array details.
608 --
609 -- p_array_name - the array name 'Potenatial Prereqs', 'Required Bugfixes', etc.
610 -- p_arg1 - optional argument, used for title, prompt etc.
611 --------------------------------------------------------------------------------
612 procedure debug_array_to_report(p_array_name in varchar2,
613                                 p_arg1       in varchar2 default null)
614 is
615    l_heading varchar2(2000);
616 
617    procedure debug_bugfix_to_report(p_bugfix_index             in binary_integer,
618                                     p_debug_application_status in boolean,
619                                     p_debug_top_level          in boolean)
620    is
621       l_bugfix bugfix;
622       l_debug  varchar2(32000);
623    begin
624       l_bugfix := g_bugfixes(p_bugfix_index);
625 
626       l_debug := lpad(l_bugfix.bugfix_id, 13) ||
627          ' ' || rpad(l_bugfix.release_status, 18);
628 
629       if (p_debug_application_status) then
630          l_debug := l_debug || ' ' || rpad(l_bugfix.application_status, 18);
631       end if;
632 
633       if (p_debug_top_level) then
634          if (l_bugfix.merged) then
635             l_debug := l_debug || ' MERGED';
636          else
637             l_debug := l_debug || ' NOT_MERGED';
638          end if;
639       end if;
640 
641       debug_to_report(l_debug);
642 
643    exception
644       when others then
645          raise_others_error('debug_bugfix_to_report',
646             g_bugfixes(p_bugfix_index).bug_number,
647             boolean_to_char(p_debug_application_status),
648             boolean_to_char(p_debug_top_level));
649    end debug_bugfix_to_report;
650 
651 begin
652    if (p_arg1 is null) then
653       l_heading := p_array_name || ': ';
654    else
655       l_heading := p_array_name || ' (' || p_arg1 || '): ';
656    end if;
657 
658    if (p_array_name = 'Top Level Bugfixes') then
659       debug_to_report(' ');
660       debug_to_report(l_heading || g_globals.top_level_bugfix_count);
661       debug_to_report('--------------------------------------------------');
662 
663       for i in 0..g_globals.top_level_bugfix_count - 1 loop
664          debug_bugfix_to_report(p_bugfix_index             => i,
665                                 p_debug_application_status => true,
666                                 p_debug_top_level          => false);
667 
668       end loop; -- top level bugfixes
669 
670    elsif (p_array_name = 'Required Bugfixes') then
671 
672       debug_to_report(' ');
673       debug_to_report(l_heading || g_globals.required_bugfix_count);
674       debug_to_report('--------------------------------------------------');
675 
676       for i in 0 .. g_globals.required_bugfix_count - 1 loop
677          debug_bugfix_to_report(p_bugfix_index             => g_globals.required_bugfix_indexes(i),
678                                 p_debug_application_status => true,
679                                 p_debug_top_level          => true);
680       end loop; -- required bugfixes
681 
682    else
683       raise_formatted_error(ERROR_UMS_ARRAY_NAME,
684          get_formatted_error('UMS Code Error in debug_array_to_report()',
685             'Unexpected array name: ' || p_array_name));
686    end if;
687 
688 exception
689    when others then
690       raise_others_error('debug_array_to_report',
691          p_array_name,
692          p_arg1);
693 end debug_array_to_report;
694 
695 --------------------------------------------------------------------------------
696 -- Creates the bugfix in cache.
697 --
698 -- p_release_name - the release name
699 -- p_bug_number - the bug number
700 -- p_language_code - the language code
701 --
702 -- return: the bugfix index
703 --------------------------------------------------------------------------------
704 function create_bugfix(p_release_name  in varchar2,
705                        p_bug_number    in number,
706                        p_language_code in varchar2)
707    return binary_integer
708 is
709    l_bugfix       bugfix;
710    l_bugfix_index binary_integer;
711 begin
712    if (p_language_code <> 'US') then
713 
714       -- NLS patch or NLS bugfix
715 
716       l_bugfix.bugfix_guid := null;
717       l_bugfix.release_name := p_release_name;
718       l_bugfix.bug_number := p_bug_number;
719       l_bugfix.download_mode := fnd_ums_loader.DL_MODE_NONE;
720       l_bugfix.application_short_name := null;
721       l_bugfix.release_status := RSTATUS_RELEASED;
722       l_bugfix.type := fnd_ums_loader.BUGFIX_TYPE_BUGFIX;
723       l_bugfix.bugfix_id := p_bug_number || ':' || p_language_code;
724 
725       if (p_language_code like 'NLS_%') then
726          l_bugfix.patch_type := PATCH_TYPE_NLS_BUGFIX;
727          l_bugfix.abstract := '<NLS Bugfix for language: ' ||
728             substr(p_language_code,5) || '>';
729       else
730          l_bugfix.patch_type := PATCH_TYPE_NLS_PATCH;
731          l_bugfix.abstract := '<NLS Patch for language: ' ||
732             p_language_code || '>';
733       end if;
734 
735    else
736       -- a 'US' bugfix
737       l_bugfix.bugfix_id := p_bug_number;
738 
739       begin
740          select 'AFUMSAEB.pls : $Revision: 120.1 $ : create_bugfix' arcs_revision,
741                 bugfix_guid,
742                 release_name,
743                 bug_number,
744                 download_mode,
745                 application_short_name,
746                 release_status,
747                 type,
748                 abstract
749            into g_arcs_revision,
750                 l_bugfix.bugfix_guid,
751                 l_bugfix.release_name,
752                 l_bugfix.bug_number,
753                 l_bugfix.download_mode,
754                 l_bugfix.application_short_name,
755                 l_bugfix.release_status,
756                 l_bugfix.type,
757                 l_bugfix.abstract
758            from fnd_ums_bugfixes
759           where release_name = p_release_name
760             and bug_number = p_bug_number
761             and download_mode <> fnd_ums_loader.DL_MODE_NONE;
762 
763          l_bugfix.patch_type := PATCH_TYPE_US_UMS;
764       exception
765          when no_data_found then
766 
767             -- non-UMS US bugfix.
768 
769             l_bugfix.patch_type := PATCH_TYPE_US_NON_UMS;
770 
771             l_bugfix.bugfix_guid := null;
772             l_bugfix.release_name := p_release_name;
773             l_bugfix.bug_number := p_bug_number;
774             l_bugfix.download_mode := fnd_ums_loader.DL_MODE_NONE;
775             l_bugfix.application_short_name := null;
776             l_bugfix.release_status := RSTATUS_RELEASED;
777             l_bugfix.type := fnd_ums_loader.BUGFIX_TYPE_BUGFIX;
778             l_bugfix.abstract := '<Patch for language: US>';
779       end;
780    end if;
781 
782    -- get ad_application_status
783    begin
784       if (l_bugfix.patch_type in (PATCH_TYPE_NLS_PATCH,
785                                   PATCH_TYPE_NLS_BUGFIX)) then
786 
787          l_bugfix.ad_application_status := ad_patch.NOT_APPLIED;
788       else
789          -- a 'US' bugfix
790          -- get bugfix application status from AD
791 
792          begin
793             l_bugfix.ad_application_status := ad_patch.is_patch_applied(
794                p_appl_top_id  => g_globals.appl_top_id,
795                p_release_name => l_bugfix.release_name,
796                p_bug_number   => l_bugfix.bug_number);
797          exception
798             when others then
799                raise_formatted_error(ERROR_AD_IS_PATCH_APPLIED,
800                   get_formatted_error('Error in AD_PATCH',
804                         l_bugfix.release_name || ''',',
801                      'ad_patch.is_patch_applied(p_appl_top_id  => ' ||
802                         g_globals.appl_top_id || ',',
803                      '                          p_release_name => ''' ||
805                      '                          p_bug_number   => ' ||
806                         l_bugfix.bug_number || ')'));
807          end;
808       end if;
809    end;
810 
811    if (l_bugfix.ad_application_status = ad_patch.EXPLICITLY_APPLIED) then
812       l_bugfix.application_status := APP_STATUS_EXPLICITLY_APPLIED;
813 
814    elsif (l_bugfix.ad_application_status = ad_patch.IMPLICITLY_APPLIED) then
815       l_bugfix.application_status := APP_STATUS_IMPLICITLY_APPLIED;
816 
817    else
818       l_bugfix.application_status := APP_STATUS_NOT_APPLIED;
819 
820    end if;
821 
822    -- Common initialization
823 
824    l_bugfix.language_code := p_language_code;
825    l_bugfix.required := false;
826    l_bugfix.merged := false;
827    l_bugfix.replacement_chain_tag := null;
828    l_bugfix.equivalency_result := null;
829    l_bugfix.equivalency_path := null;
830    l_bugfix.equivalent_bugfix_index := null;
831 
832    -- Bugfix record is ready, assign the primary key.
833 
834    l_bugfix_index := g_globals.bugfix_count;
835 
836    g_globals.bugfix_count := g_globals.bugfix_count + 1;
837 
838    l_bugfix.bugfix_index := l_bugfix_index;
839 
840    g_bugfixes(l_bugfix_index) := l_bugfix;
841 
842    return l_bugfix.bugfix_index;
843 
844 exception
845    when others then
846       raise_others_error('create_bugfix',
847          p_release_name,
848          p_bug_number,
849          p_language_code);
850 end create_bugfix;
851 
852 --------------------------------------------------------------------------------
853 -- Gets the bugfix.  If the bugfix does not exist, a new one is created.  This
854 -- function is useful if you only need a handle to the bugfix for read access.
855 -- Since the returned bugfix is a copy of the one in the global array, it is
856 -- not useful for write access.
857 --
858 -- p_release_name - the release name
859 -- p_bug_number - the bug number
860 -- p_language_code - the language code
861 --
862 -- return: the bugfix
863 --------------------------------------------------------------------------------
864 function get_bugfix(p_release_name  in varchar2,
865                     p_bug_number    in number,
866                     p_language_code in varchar2)
867    return bugfix
868 is
869    l_bugfix       bugfix;
870    l_bugfix_index binary_integer;
871    l_found        boolean;
872 begin
873    l_found := false;
874 
875    for i in reverse 0 .. g_globals.bugfix_count - 1 loop
876       if (g_bugfixes(i).release_name = p_release_name and
877           g_bugfixes(i).bug_number = p_bug_number and
878           g_bugfixes(i).language_code = p_language_code) then
879          l_bugfix := g_bugfixes(i);
880          l_found := true;
881 
882          exit;
883       end if;
884    end loop;
885 
886    if (not l_found) then
887       l_bugfix_index := create_bugfix(p_release_name,
888                                       p_bug_number,
889                                       p_language_code);
890       l_bugfix := g_bugfixes(l_bugfix_index);
891    end if;
892 
893    return l_bugfix;
894 
895 exception
896    when others then
897       raise_others_error('get_bugfix',
898          p_release_name,
899          p_bug_number,
900          p_language_code);
901 end get_bugfix;
902 
903 --------------------------------------------------------------------------------
904 -- Gets the bugfix for UMS bugfixes.
905 --
906 -- p_bugfix_guid - the bugfix guid
907 --
908 -- return: the bugfix
909 --------------------------------------------------------------------------------
910 function get_bugfix(p_bugfix_guid in fnd_ums_bugfixes.bugfix_guid%type)
911    return bugfix
912 is
913    l_release_name fnd_ums_bugfixes.release_name%type;
914    l_bug_number   fnd_ums_bugfixes.bug_number%type;
915    l_bugfix_index binary_integer;
916    l_bugfix       bugfix;
917    l_found        boolean;
918 begin
919    l_found := false;
920 
921    for i in reverse 0 .. g_globals.bugfix_count - 1 loop
922       if (g_bugfixes(i).bugfix_guid = p_bugfix_guid) then
923          l_bugfix := g_bugfixes(i);
924          l_found := true;
925 
926          exit;
927       end if;
928    end loop;
929 
930    if (not l_found) then
931       -- Check UMS table
932       begin
933          select 'AFUMSAEB.pls : $Revision: 120.1 $ : get_bugfix' arcs_revision,
934                 release_name,
935                 bug_number
936            into g_arcs_revision,
937                 l_release_name,
938                 l_bug_number
939            from fnd_ums_bugfixes
940           where bugfix_guid = p_bugfix_guid;
941       exception
942          when no_data_found then
943             raise_formatted_error(ERROR_UMS_MISSING_DATA,
944                get_formatted_error('No data found in FND_UMS_BUGFIXES',
945                   'for bugfix guid ' || p_bugfix_guid));
946       end;
950                                       'US');
947 
948       l_bugfix_index := create_bugfix(l_release_name,
949                                       l_bug_number,
951       l_bugfix := g_bugfixes(l_bugfix_index);
952 
953    end if;
954 
955    return l_bugfix;
956 
957 exception
958    when others then
959       raise_others_error('get_bugfix',
960          p_bugfix_guid);
961 end get_bugfix;
962 
963 --------------------------------------------------------------------------------
964 -- Sets/unsets required state of a bugfix
965 --
966 -- p_bugfix_index - bugfix index
967 -- p_required - required state of a bugfix
968 --------------------------------------------------------------------------------
969 procedure set_bugfix_required(p_bugfix_index in binary_integer,
970                               p_required     in boolean)
971 is
972    l_required boolean;
973 begin
974    l_required := g_bugfixes(p_bugfix_index).required;
975 
976    if (l_required) then
977       if (not p_required) then
978          --
979          -- REQUIRED --> NOT REQUIRED
980          --
981          -- remove it from required bugfixes
982          for i in 0 .. g_globals.required_bugfix_count - 1 loop
983             if (g_globals.required_bugfix_indexes(i) = p_bugfix_index) then
984 
985                g_globals.required_bugfix_indexes(i) :=
986                   g_globals.required_bugfix_indexes(g_globals.required_bugfix_count - 1);
987                g_globals.required_bugfix_count := g_globals.required_bugfix_count - 1;
988 
989                exit; -- from the loop
990             end if;
991          end loop;
992       end if;
993    else
994       if (p_required) then
995          --
996          -- NOT REQUIRED --> REQUIRED
997          --
998          -- add it to required bugfixes
999          g_globals.required_bugfix_indexes(g_globals.required_bugfix_count) := p_bugfix_index;
1000          g_globals.required_bugfix_count := g_globals.required_bugfix_count + 1;
1001       end if;
1002    end if;
1003 
1004    g_bugfixes(p_bugfix_index).required := p_required;
1005 
1006 exception
1007    when others then
1008       raise_others_error('set_bugfix_required',
1009          g_bugfixes(p_bugfix_index).bug_number,
1010          boolean_to_char(p_required));
1011 end set_bugfix_required;
1012 
1013 --------------------------------------------------------------------------------
1014 -- Gets the replacement bugfix guid.
1015 --
1016 -- p_bugfix_guid - the bugfix guid
1017 --
1018 -- return: the replacement bugfix guid or null if there is no replacement
1019 --------------------------------------------------------------------------------
1020 function get_replacement_bugfix_guid(p_bugfix_guid in fnd_ums_bugfixes.bugfix_guid%type)
1021    return fnd_ums_bugfixes.bugfix_guid%type
1022 is
1023    l_replacement_bugfix_guid fnd_ums_bugfixes.bugfix_guid%type;
1024 begin
1025    begin
1026       select 'AFUMSAEB.pls : $Revision: 120.1 $ : get_replacement_bugfix_guid' arcs_revision,
1027              related_bugfix_guid
1028         into g_arcs_revision,
1029              l_replacement_bugfix_guid
1030         from fnd_ums_bugfix_relationships
1031        where bugfix_guid = p_bugfix_guid
1032          and relation_type = fnd_ums_loader.REL_TYPE_REPLACED_BY;
1033    exception
1034       when no_data_found then
1035          -- there is no replacement
1036 
1037          l_replacement_bugfix_guid := null;
1038    end;
1039 
1040    return l_replacement_bugfix_guid;
1041 
1042 exception
1043    when others then
1044       raise_others_error('get_replacement_bugfix_guid',
1045          get_bugfix(p_bugfix_guid).bug_number);
1046 end get_replacement_bugfix_guid;
1047 
1048 --------------------------------------------------------------------------------
1049 -- Returns the replacement chain of a bugfix up to
1050 --    the end of the chain
1051 --
1052 -- p_bugfix_index - the bugfix index
1053 -- px_replacement_chain - the replacement chain
1054 --------------------------------------------------------------------------------
1055 procedure get_full_replacement_chain(p_bugfix_index       in binary_integer,
1056                                      px_replacement_chain in out nocopy replacement_chain)
1057 is
1058    l_bugfix      bugfix;
1059    l_bugfix_guid fnd_ums_bugfixes.bugfix_guid%type;
1060 begin
1061    px_replacement_chain.bugfix_count := 0;
1062 
1063    g_globals.replacement_chain_tag_counter := g_globals.replacement_chain_tag_counter + 1;
1064 
1065    l_bugfix := g_bugfixes(p_bugfix_index);
1066    l_bugfix_guid := l_bugfix.bugfix_guid;
1067 
1068    loop
1069       px_replacement_chain.bugfix_indexes(px_replacement_chain.bugfix_count) := l_bugfix.bugfix_index;
1070       px_replacement_chain.bugfix_count := px_replacement_chain.bugfix_count + 1;
1071 
1072       -- check for cyclic replacement chain
1073 
1074       if (l_bugfix.replacement_chain_tag = g_globals.replacement_chain_tag_counter) then
1075          px_replacement_chain.bugfix_count := px_replacement_chain.bugfix_count - 1;
1076          exit;  -- from chain loop
1077       else
1078          -- tag it
1079          g_bugfixes(l_bugfix.bugfix_index).replacement_chain_tag := g_globals.replacement_chain_tag_counter;
1080       end if;
1081 
1085          -- the end of the replacement chain has been reached
1082       l_bugfix_guid := get_replacement_bugfix_guid(l_bugfix_guid);
1083 
1084       if (l_bugfix_guid is null) then
1086 
1087          exit;  -- from chain loop
1088       end if;
1089 
1090       -- next bugfix in the chain
1091 
1092       l_bugfix := get_bugfix(l_bugfix_guid);
1093    end loop;
1094 
1095 exception
1096    when others then
1097       raise_others_error('get_full_replacement_chain',
1098          g_bugfixes(p_bugfix_index).bug_number);
1099 end get_full_replacement_chain;
1100 
1101 --------------------------------------------------------------------------------
1102 -- Gets the replacement bugfix guid.
1103 --
1104 -- p_bugfix_guid - the bugfix guid
1105 -- p_replacement_type - type of the replacement.
1106 --
1107 -- return: the replacement bugfix guid or null if there is no replacement
1108 --
1109 --          OR         OR            OR         OR
1110 --   Aobs ------> A1 ------> A2obs ------> A3 ------> A4obs
1111 --
1112 --  p_bugfix_guid p_replacement_type              return
1113 --  ------------- ------------------------------- --------
1114 --  Aobs          REPLACEMENT_ORIGINAL            A1
1115 --  Aobs          REPLACEMENT_FIRST_NON_OBSOLETE  A1
1116 --  Aobs          REPLACEMENT_LAST_NON_OBSOLETE   A3
1117 --
1118 --  A1            REPLACEMENT_ORIGINAL            A2obs
1119 --  A1            REPLACEMENT_FIRST_NON_OBSOLETE  A3
1120 --  A1            REPLACEMENT_LAST_NON_OBSOLETE   A3
1121 --
1122 --  A2obs         REPLACEMENT_ORIGINAL            A3
1123 --  A2obs         REPLACEMENT_FIRST_NON_OBSOLETE  A3
1124 --  A2obs         REPLACEMENT_LAST_NON_OBSOLETE   A3
1125 --
1126 --  A3            REPLACEMENT_ORIGINAL            A4obs
1127 --  A3            REPLACEMENT_FIRST_NON_OBSOLETE  null
1128 --  A3            REPLACEMENT_LAST_NON_OBSOLETE   null
1129 --
1130 --  A4obs         REPLACEMENT_ORIGINAL            null
1131 --  A4obs         REPLACEMENT_FIRST_NON_OBSOLETE  null
1132 --  A4obs         REPLACEMENT_LAST_NON_OBSOLETE   null
1133 --
1134 --------------------------------------------------------------------------------
1135 function get_replacement_bugfix_guid(p_bugfix_guid      in fnd_ums_bugfixes.bugfix_guid%type,
1136                                      p_replacement_type in varchar2)
1137    return fnd_ums_bugfixes.bugfix_guid%type
1138 is
1139    l_replacement_bugfix_guid fnd_ums_bugfixes.bugfix_guid%type;
1140    l_bugfix                  bugfix;
1141    l_replacement_chain       replacement_chain;
1142 begin
1143    l_replacement_bugfix_guid := null;
1144 
1145    l_bugfix := get_bugfix(p_bugfix_guid);
1146 
1147    get_full_replacement_chain(l_bugfix.bugfix_index, l_replacement_chain);
1148 
1149    if (p_replacement_type = REPLACEMENT_ORIGINAL) then
1150 
1151       for i in 1 .. l_replacement_chain.bugfix_count - 1 loop
1152          if (i = 1) then
1153             l_replacement_bugfix_guid := g_bugfixes(l_replacement_chain.bugfix_indexes(i)).bugfix_guid;
1154             exit;
1155          end if;
1156       end loop;
1157 
1158    elsif (p_replacement_type = REPLACEMENT_FIRST_NON_OBSOLETE) then
1159 
1160       for i in 1 .. l_replacement_chain.bugfix_count - 1 loop
1161          if (g_bugfixes(l_replacement_chain.bugfix_indexes(i)).release_status <> RSTATUS_OBSOLETED) then
1162             l_replacement_bugfix_guid := g_bugfixes(l_replacement_chain.bugfix_indexes(i)).bugfix_guid;
1163             exit;
1164          end if;
1165       end loop;
1166 
1167    elsif (p_replacement_type = REPLACEMENT_LAST_NON_OBSOLETE) then
1168 
1169       for i in reverse 1 .. l_replacement_chain.bugfix_count - 1 loop
1170          if (g_bugfixes(l_replacement_chain.bugfix_indexes(i)).release_status <> RSTATUS_OBSOLETED) then
1171             l_replacement_bugfix_guid := g_bugfixes(l_replacement_chain.bugfix_indexes(i)).bugfix_guid;
1172             exit;
1173          end if;
1174       end loop;
1175 
1176    else
1177       raise_formatted_error(ERROR_UMS_REPLACEMENT_TYPE,
1178          get_formatted_error('UMS Code Error in get_replacement_bugfix_guid()',
1179             'Unexpected replacement type: ' || p_replacement_type));
1180    end if;
1181 
1182    return l_replacement_bugfix_guid;
1183 
1184 exception
1185    when others then
1186       raise_others_error('get_replacement_bugfix_guid',
1187          get_bugfix(p_bugfix_guid).bug_number,
1188          p_replacement_type);
1189 end get_replacement_bugfix_guid;
1190 
1191 --------------------------------------------------------------------------------
1192 procedure check_bugfix_required(p_bugfix_index         in binary_integer,
1193                                 p_relation_type        in varchar2,
1194                                 p_related_bugfix_index in binary_integer)
1195 is
1196    l_debug_bugfix   bugfix;
1197    l_related_bugfix bugfix;
1198 begin
1199    l_related_bugfix := g_bugfixes(p_related_bugfix_index);
1200 
1201    if (g_globals.debug_on) then
1202       l_debug_bugfix := g_bugfixes(p_bugfix_index);
1203 
1204       debug_to_report('Checking (' || l_debug_bugfix.bugfix_id || ' ' ||
1205          p_relation_type || ' ' ||
1206          l_related_bugfix.bugfix_id || ')');
1207       g_globals.indent_level := g_globals.indent_level + 1;
1208    end if;
1209 
1213          debug_to_report('Bugfix ' ||
1210    if (l_related_bugfix.application_status in (APP_STATUS_EXPLICITLY_APPLIED,
1211                                                APP_STATUS_IMPLICITLY_APPLIED)) then
1212       if (g_globals.debug_on) then
1214             l_related_bugfix.bug_number ||
1215             ' is ' || l_related_bugfix.application_status || ', so it is not required.');
1216       end if;
1217    else
1218       if (g_globals.debug_on) then
1219          debug_to_report('Bugfix ' ||
1220             l_related_bugfix.bug_number ||
1221             ' is not applied, so it is required.');
1222       end if;
1223 
1224       --
1225       -- This bugfix is required.
1226       --
1227       set_bugfix_required(p_related_bugfix_index, true);
1228    end if;
1229 
1230    if (g_globals.debug_on) then
1231       g_globals.indent_level := g_globals.indent_level - 1;
1232    end if;
1233 
1234 exception
1235    when others then
1236       raise_others_error('check_bugfix_required',
1237          g_bugfixes(p_bugfix_index).bug_number,
1238          p_relation_type,
1239          g_bugfixes(p_related_bugfix_index).bug_number);
1240 end check_bugfix_required;
1241 
1242 --------------------------------------------------------------------------------
1243 procedure check_bugfix_prereqs(p_bugfix_index in binary_integer)
1244 is
1245    --
1246    -- order by is added to get reproducible results in RT.
1247    --
1248    cursor l_prereqs(p_bugfix_guid fnd_ums_bugfixes.bugfix_guid%type) is
1249       select 'AFUMSAEB.pls : $Revision: 120.1 $ : check_bugfix_prereqs' arcs_revision,
1250              fubr.related_bugfix_guid,
1251              fubr.relation_type
1252         from fnd_ums_bugfix_relationships fubr,
1253              fnd_ums_bugfixes fub
1254        where fubr.bugfix_guid = p_bugfix_guid
1255         --
1256         -- - Direct/Indirect Prereq links are followed
1257         --
1258         --   fubr.related_bugfix
1259         --    /|\
1260         --     |
1261         --     |P/P'
1262         --     |
1263         --     |
1264         --   fubr.bugfix
1265         --
1266          and fubr.relation_type in (fnd_ums_loader.REL_TYPE_PREREQS,
1267                                     fnd_ums_loader.REL_TYPE_INDIRECTLY_PREREQS)
1268          and fub.bugfix_guid = fubr.related_bugfix_guid
1269        order by decode(fubr.relation_type,
1270                        fnd_ums_loader.REL_TYPE_INDIRECTLY_PREREQS,  1,
1271                        fnd_ums_loader.REL_TYPE_PREREQS,             2,
1272                        99),
1273                 fub.bug_number;
1274 
1275    l_bugfix         bugfix;
1276    l_related_bugfix bugfix;
1277 begin
1278    l_bugfix := g_bugfixes(p_bugfix_index);
1279 
1280    if (g_globals.debug_on) then
1281       debug_to_report('BEGIN bugfix ' || l_bugfix.bugfix_id);
1282 
1283       g_globals.indent_level := g_globals.indent_level + 1;
1284 
1285       debug_to_report('release status = ' || l_bugfix.release_status);
1286       debug_to_report('AD application status = ' || l_bugfix.ad_application_status);
1287    end if;
1288 
1289    if (l_bugfix.patch_type = PATCH_TYPE_NLS_PATCH) then
1290       -- NLS Patch. Create a Prereq link on the fly to the 'US' version of
1291       -- the same bugfix.
1292 
1293       l_related_bugfix := get_bugfix(p_release_name  => l_bugfix.release_name,
1294                                      p_bug_number    => l_bugfix.bug_number,
1295                                      p_language_code => 'US');
1296 
1297       if (g_globals.debug_on) then
1298          debug_to_report('NLS Patch: need to check US patch and its prereqs.');
1299       end if;
1300 
1301       check_bugfix_required(l_bugfix.bugfix_index,
1302                             fnd_ums_loader.REL_TYPE_PREREQS,
1303                             l_related_bugfix.bugfix_index);
1304 
1305       if (g_bugfixes(l_related_bugfix.bugfix_index).required) then
1306          check_bugfix_prereqs(l_related_bugfix.bugfix_index);
1307       end if;
1308 
1309    elsif (l_bugfix.patch_type = PATCH_TYPE_NLS_BUGFIX) then
1310       -- NLS bugfix
1311 
1312       if (g_globals.debug_on) then
1313          debug_to_report('NLS Bugfix: there is nothing to do.');
1314       end if;
1315 
1316    elsif (l_bugfix.patch_type = PATCH_TYPE_US_NON_UMS) then
1317       -- US patch without metadata
1318 
1319       if (g_globals.debug_on) then
1320          debug_to_report('US, Non-UMS Patch: there is nothing to do.');
1321       end if;
1322 
1323    elsif (l_bugfix.patch_type = PATCH_TYPE_US_UMS) then
1324       -- US patch with metadata
1325 
1326       if (g_globals.debug_on) then
1327          debug_to_report('US Patch: need to check prereqs.');
1328       end if;
1329 
1330       for l_prereq in l_prereqs(l_bugfix.bugfix_guid) loop
1331          l_related_bugfix := get_bugfix(l_prereq.related_bugfix_guid);
1332 
1333          check_bugfix_required(l_bugfix.bugfix_index,
1334                                l_prereq.relation_type,
1335                                l_related_bugfix.bugfix_index);
1336       end loop;
1337    else
1338       raise_formatted_error(ERROR_UMS_PATCH_TYPE,
1339          get_formatted_error('UMS Code Error: ',
1340             'Unexpected patch type: ' || l_bugfix.patch_type));
1341    end if;
1342 
1346    end if;
1343    if (g_globals.debug_on) then
1344       g_globals.indent_level := g_globals.indent_level - 1;
1345       debug_to_report('END bugfix ' || l_bugfix.bugfix_id);
1347 
1348 exception
1349    when others then
1350       raise_others_error('check_bugfix_prereqs',
1351          g_bugfixes(p_bugfix_index).bug_number);
1352 end check_bugfix_prereqs;
1353 
1354 --------------------------------------------------------------------------------
1355 function get_equivalency_result(p_bugfix_index  in binary_integer,
1356                                 p_incoming_path in varchar2)
1357    return varchar2
1358 is
1359    cursor l_equivalents(p_bugfix_guid fnd_ums_bugfixes.bugfix_guid%type) is
1360       select alias_bugfix_guid,
1361              alias_relation_type
1362         from (select fubr.related_bugfix_guid alias_bugfix_guid,
1363                      fubr.relation_type alias_relation_type
1364                 from fnd_ums_bugfix_relationships fubr
1365                where fubr.bugfix_guid = p_bugfix_guid
1366                  and fubr.relation_type = fnd_ums_loader.REL_TYPE_REPLACED_BY
1367               union
1368               select fubr.bugfix_guid alias_bugfix_guid,
1369                      fubr.relation_type alias_relation_type
1370                 from fnd_ums_bugfix_relationships fubr
1371                where fubr.related_bugfix_guid = p_bugfix_guid
1372                  and fubr.relation_type in (fnd_ums_loader.REL_TYPE_INCLUDES,
1373                                             fnd_ums_loader.REL_TYPE_INDIRECTLY_INCLUDES)) rels,
1374              fnd_ums_bugfixes fub
1375        where 'AFUMSAEB.pls : $Revision: 120.1 $ : get_equivalency_result' is not null
1376          and rels.alias_bugfix_guid = fub.bugfix_guid
1377        order by decode(alias_relation_type,
1378                        fnd_ums_loader.REL_TYPE_REPLACED_BY, 1,
1379                        fnd_ums_loader.REL_TYPE_INDIRECTLY_INCLUDES, 2,
1380                        fnd_ums_loader.REL_TYPE_INCLUDES, 3,
1381                        99),
1382                 fub.bug_number;
1383 
1384    l_bugfix_guids       BUGFIX_GUID_ARRAY;
1385    l_relation_types     RELATION_TYPE_ARRAY;
1386 
1387    l_bugfix             bugfix;
1388    l_equivalent_bugfix  bugfix;
1389    l_vc2                varchar2(32000);
1390    l_equivalency_result varchar2(30);
1391 begin
1392    -- Since this function is called, increment the call count
1393 
1394    g_globals.get_equivalency_call_count := g_globals.get_equivalency_call_count + 1;
1395 
1396    if (g_globals.get_equivalency_call_count > MAX_GET_EQUIVALENCY_CALL_COUNT) then
1397       g_bugfixes(p_bugfix_index).equivalency_result := EQUIVALENCY_TERMINATED;
1398       g_bugfixes(p_bugfix_index).equivalency_path := null;
1399       g_bugfixes(p_bugfix_index).equivalent_bugfix_index := null;
1400 
1401       goto done;
1402    end if;
1403 
1404    l_bugfix := g_bugfixes(p_bugfix_index);
1405 
1406    if (l_bugfix.equivalency_result is null) then
1407       -- This is the first time this bugfix is visited.
1408 
1409       null;
1410    elsif (l_bugfix.equivalency_result = EQUIVALENCY_TERMINATED) then
1411       -- This bugfix was terminated, it needs to be re-visited.
1412 
1413       null;
1414    elsif (l_bugfix.equivalency_result = EQUIVALENCY_IN_PROGRESS) then
1415       -- An equivalency cycle exists.
1416 
1417       goto done;
1418    elsif (l_bugfix.equivalency_result in (EQUIVALENCY_COMPLETED_NONE,
1419                                           EQUIVALENCY_COMPLETED_REQUIRED,
1420                                           EQUIVALENCY_COMPLETED_MERGED,
1421                                           EQUIVALENCY_COMPLETED_APPLIED)) then
1422       -- Equivalency visitation was complete for this bugfix.
1423 
1424       goto done;
1425    end if;
1426 
1427    if (g_globals.debug_on) then
1428       debug_to_report(p_incoming_path ||
1429          ', ' || g_bugfixes(p_bugfix_index).equivalency_result);
1430    end if;
1431 
1432    -- This bugfix needs to be processed for equivalency check
1433 
1434    if (l_bugfix.application_status in (APP_STATUS_EXPLICITLY_APPLIED,
1435                                        APP_STATUS_IMPLICITLY_APPLIED)) then
1436       g_bugfixes(p_bugfix_index).equivalency_result := EQUIVALENCY_COMPLETED_APPLIED;
1437       g_bugfixes(p_bugfix_index).equivalency_path := null;
1438       g_bugfixes(p_bugfix_index).equivalent_bugfix_index := p_bugfix_index;
1439 
1440       goto done;
1441    end if;
1442 
1443    if (l_bugfix.merged) then
1444       g_bugfixes(p_bugfix_index).equivalency_result := EQUIVALENCY_COMPLETED_MERGED;
1445       g_bugfixes(p_bugfix_index).equivalency_path := null;
1446       g_bugfixes(p_bugfix_index).equivalent_bugfix_index := p_bugfix_index;
1447 
1448       goto done;
1449    end if;
1450 
1451    g_bugfixes(p_bugfix_index).equivalency_result := EQUIVALENCY_IN_PROGRESS;
1452 
1453    open l_equivalents(l_bugfix.bugfix_guid);
1454 
1455    fetch l_equivalents bulk collect into l_bugfix_guids, l_relation_types
1456       limit MAX_GET_EQUIVALENCY_CALL_COUNT + 1 - g_globals.get_equivalency_call_count;
1457 
1458    close l_equivalents;
1459 
1460    for i in 1 .. l_bugfix_guids.count loop
1461       l_equivalent_bugfix := get_bugfix(l_bugfix_guids(i));
1462 
1463       if (l_relation_types(i) = fnd_ums_loader.REL_TYPE_REPLACED_BY) then
1464          l_vc2 := ' -OR-> ';
1465       elsif (l_relation_types(i) = fnd_ums_loader.REL_TYPE_INCLUDES) then
1469       end if;
1466          l_vc2 := ' <-I- ';
1467       elsif (l_relation_types(i) = fnd_ums_loader.REL_TYPE_INDIRECTLY_INCLUDES) then
1468          l_vc2 := ' <-I''- ';
1470       l_vc2 := l_vc2 || l_equivalent_bugfix.bug_number;
1471 
1472       l_equivalency_result := get_equivalency_result(l_equivalent_bugfix.bugfix_index,
1473                                                      p_incoming_path || l_vc2);
1474 
1475       if (l_equivalency_result = EQUIVALENCY_TERMINATED) then
1476          g_bugfixes(p_bugfix_index).equivalency_result := l_equivalency_result;
1477          g_bugfixes(p_bugfix_index).equivalency_path := null;
1478          g_bugfixes(p_bugfix_index).equivalent_bugfix_index := null;
1479 
1480          goto done;
1481       elsif (l_equivalency_result in (EQUIVALENCY_COMPLETED_REQUIRED,
1482                                       EQUIVALENCY_COMPLETED_MERGED,
1483                                       EQUIVALENCY_COMPLETED_APPLIED)) then
1484 
1485          g_bugfixes(p_bugfix_index).equivalency_result := l_equivalency_result;
1486          g_bugfixes(p_bugfix_index).equivalency_path :=
1487             l_vc2 || g_bugfixes(l_equivalent_bugfix.bugfix_index).equivalency_path;
1488          g_bugfixes(p_bugfix_index).equivalent_bugfix_index :=
1489             g_bugfixes(l_equivalent_bugfix.bugfix_index).equivalent_bugfix_index;
1490 
1491          goto done;
1492       end if;
1493    end loop;
1494 
1495    if (l_bugfix.required) then
1496       g_bugfixes(p_bugfix_index).equivalency_result := EQUIVALENCY_COMPLETED_REQUIRED;
1497       g_bugfixes(p_bugfix_index).equivalency_path := null;
1498       g_bugfixes(p_bugfix_index).equivalent_bugfix_index := p_bugfix_index;
1499 
1500       goto done;
1501    end if;
1502 
1503    g_bugfixes(p_bugfix_index).equivalency_result := EQUIVALENCY_COMPLETED_NONE;
1504    g_bugfixes(p_bugfix_index).equivalency_path := null;
1505    g_bugfixes(p_bugfix_index).equivalent_bugfix_index := null;
1506 
1507    goto done;
1508 
1509    <<done>>
1510    if (g_globals.debug_on) then
1511       debug_to_report(p_incoming_path ||
1512          ', ' || g_bugfixes(p_bugfix_index).equivalency_result);
1513    end if;
1514 
1515    return g_bugfixes(p_bugfix_index).equivalency_result;
1516 exception
1517    when others then
1518       raise_others_error('get_equivalency_result',
1519          g_bugfixes(p_bugfix_index).bug_number,
1520          p_incoming_path);
1521 end get_equivalency_result;
1522 
1523 --------------------------------------------------------------------------------
1524 -- Equivalency Removal
1525 --    A required bugfix can be removed if
1526 --    -- it or one of its equivalents is applied, or
1527 --    -- it or one of its equivalents is merged, or
1528 --    --       one of its equivalents is also a required bugfix.
1529 --
1530 -- Equivalency: Bugfix 2 is equivalent to Bugfix 1 if
1531 --    -- Bugfix 2 replaces Bugfix 1 or one of its equivalents, or
1532 --    -- Bugfix 2 includes Bugfix 1 or one of its equivalents
1533 --
1534 --
1535 -- In following pictures Bugfix 2 is equivalent to Bugfix 1.
1536 --
1537 --    -- Bugfix 2 replaces Bugfix 1
1538 --
1539 --               1 -----> 2
1540 --
1541 --    -- Bugfix 2 includes Bugfix 1
1542 --
1543 --               1
1544 --              /|\
1545 --               |
1546 --             I |
1547 --               |
1548 --               2
1549 --
1550 --    -- Bugfix 2 replaces one of Bugfix 1's equivalents
1551 --
1552 --               1 -----> 3 -----> 2
1553 --
1554 --
1555 --               1
1556 --              /|\
1557 --               |
1558 --             I |
1559 --               |
1560 --               3 -----> 2
1561 --
1562 --
1563 --               1
1564 --                \_
1565 --                  \_
1566 --                    \_
1567 --                      \
1568 --                       3 -----> 2
1569 --
1570 --    -- Bugfix 2 includes one of Bugfix 1's equivalents
1571 --
1572 --               1 -----> 3
1573 --                       /|\
1574 --                        |
1575 --                        | I
1576 --                        |
1577 --                        2
1578 --
1579 --
1580 --               1
1581 --              /|\
1582 --               |
1583 --             I |
1584 --               |
1585 --               3
1586 --              /|\
1587 --               |
1588 --             I |
1589 --               |
1590 --               2
1591 --
1592 --
1593 --               1
1594 --                \_
1595 --                  \_
1596 --                    \_
1597 --                      \
1598 --                       3
1599 --                      /|\
1600 --                       |
1601 --                     I |
1602 --                       |
1603 --                       2
1604 --
1605 --------------------------------------------------------------------------------
1606 procedure do_equivalency_removal
1607 is
1608    l_required_bugfix_count   binary_integer;
1609    l_required_bugfix_indexes BINARY_INTEGER_ARRAY;
1610 
1611    l_bugfix_index       binary_integer;
1612    l_equivalency_result varchar2(30);
1613 begin
1614    -- Copy current required bugfix indexes to a local array
1615 
1619    end loop;
1616    l_required_bugfix_count := g_globals.required_bugfix_count;
1617    for i in 0 .. g_globals.required_bugfix_count - 1 loop
1618       l_required_bugfix_indexes(i) := g_globals.required_bugfix_indexes(i);
1620 
1621    for i in 0 .. l_required_bugfix_count - 1 loop
1622 
1623       l_bugfix_index := l_required_bugfix_indexes(i);
1624 
1625       if (g_globals.debug_on) then
1626          if (i > 0) then
1627             debug_to_report('');
1628          end if;
1629          debug_to_report('Post processing ' || g_bugfixes(l_bugfix_index).bug_number);
1630          g_globals.indent_level := g_globals.indent_level + 1;
1631       end if;
1632 
1633       -- Get equivalency result of this bugfix
1634 
1635       g_globals.get_equivalency_call_count := 0;
1636 
1637       l_equivalency_result := get_equivalency_result(l_bugfix_index,
1638                                                      g_bugfixes(l_bugfix_index).bug_number);
1639 
1640       if (g_globals.debug_on) then
1641          debug_to_report('Number of get_equivalency_result() calls : ' || g_globals.get_equivalency_call_count);
1642       end if;
1643 
1644       if (((l_equivalency_result = EQUIVALENCY_COMPLETED_REQUIRED) and
1645            (g_bugfixes(l_bugfix_index).equivalent_bugfix_index <> l_bugfix_index)) or
1646           (l_equivalency_result in (EQUIVALENCY_COMPLETED_MERGED,
1647                                     EQUIVALENCY_COMPLETED_APPLIED))) then
1648 
1649          set_bugfix_required(l_bugfix_index, false);
1650 
1651          if (g_globals.debug_on) then
1652             debug_to_report('Equivalency Removal: ' ||
1653                g_bugfixes(l_bugfix_index).bugfix_id ||
1654                ' is not required since it has an ' ||
1655                l_equivalency_result || ' equivalent bugfix.');
1656             debug_to_report('Equivalency Path : ' ||
1657                g_bugfixes(l_bugfix_index).bug_number ||
1658                g_bugfixes(l_bugfix_index).equivalency_path);
1659          end if; -- debug
1660       end if;
1661 
1662       if (g_globals.debug_on) then
1663          g_globals.indent_level := g_globals.indent_level - 1;
1664       end if;
1665    end loop; -- init_required_bugfix_indexes
1666 
1667 exception
1668    when others then
1669       raise_others_error('do_equivalency_removal');
1670 end do_equivalency_removal;
1671 
1672 --------------------------------------------------------------------------------
1673 procedure post_process_required_bugfixes
1674 is
1675    l_count number;
1676 begin
1677    if (g_globals.required_bugfix_count > 0) then
1678       if (g_globals.debug_on) then
1679          l_count := g_globals.required_bugfix_count;
1680          debug_to_report(' ');
1681          debug_to_report('Post processing required bugfixes');
1682          debug_to_report('--------------------------------------------------');
1683       end if;
1684 
1685       do_equivalency_removal();
1686 
1687       if (g_globals.debug_on) then
1688          l_count := l_count - g_globals.required_bugfix_count;
1689 
1690          debug_to_report('--------------------------------------------------');
1691          if (l_count = 0) then
1692             debug_to_report('Nothing was removed from the required bugfixes list.');
1693          else
1694             if (l_count = 1) then
1695                debug_to_report('1 bugfix was removed from the required bugfixes list.');
1696             else
1697                debug_to_report(l_count || ' bugfixes were removed from the required bugfixes list.');
1698             end if;
1699             debug_array_to_report('Required Bugfixes');
1700          end if;
1701       end if;
1702    end if;
1703 exception
1704    when others then
1705       raise_others_error('post_process_required_bugfixes');
1706 end post_process_required_bugfixes;
1707 
1708 --------------------------------------------------------------------------------
1709 -- Gets the return status.
1710 --
1711 -- return: the return status
1712 --------------------------------------------------------------------------------
1713 function get_return_status
1714    return varchar2
1715 is
1716    l_status                     varchar2(30);
1717    l_all_top_level_bugs_applied boolean;
1718    l_missing_top_level_bug_info boolean;
1719 begin
1720    l_status := null;
1721 
1722    -- STATUS_ERROR
1723    -- Code doesn't come here in case of error.
1724 
1725    -- STATUS_OBSOLETED
1726 
1727    if (g_globals.obs_top_level_bugfix_exists) then
1728       -- there is an obsolete top-level bugfix
1729 
1730       l_status := STATUS_OBSOLETED;
1731       goto done;
1732    end if;
1733 
1734    -- STATUS_MISSING
1735 
1736    if (g_globals.required_bugfix_count > 0) then
1737       -- there is a missing prereq
1738 
1739       l_status := STATUS_MISSING;
1740       goto done;
1741    end if;
1742 
1743    -- STATUS_APPLIED
1744 
1745    l_all_top_level_bugs_applied := true;
1746 
1747    for i in 0 .. g_globals.top_level_bugfix_count - 1 loop
1748       if (g_bugfixes(i).application_status <> APP_STATUS_EXPLICITLY_APPLIED) then
1749          l_all_top_level_bugs_applied := false;
1750          exit;
1751       end if;
1752    end loop;
1753 
1754    if (l_all_top_level_bugs_applied) then
1758       goto done;
1755       -- all top-level bugfixes are already applied
1756 
1757       l_status := STATUS_APPLIED;
1759    end if;
1760 
1761    -- STATUS_NO_INFORMATION
1762 
1763    l_missing_top_level_bug_info := false;
1764 
1765    for i in 0 .. g_globals.top_level_bugfix_count - 1 loop
1766       if ((g_bugfixes(i).application_status <> APP_STATUS_EXPLICITLY_APPLIED) and
1767           (g_bugfixes(i).patch_type = PATCH_TYPE_US_NON_UMS)) then
1768          l_missing_top_level_bug_info := true;
1769          exit;
1770       end if;
1771    end loop;
1772 
1773    if (l_missing_top_level_bug_info) then
1774       -- at least one un-applied top-level bugfix is a US_NON_UMS bugfix
1775 
1776       l_status := STATUS_NO_INFORMATION;
1777       goto done;
1778    end if;
1779 
1780    -- STATUS_READY;
1781 
1782    -- none of the top-level bugfixes is obsolete
1783    -- nothing is missing
1784    -- at least one bugfix is unapplied
1785    -- none of the unapplied top-level bugfixes is US_NON_UMS
1786 
1787    l_status := STATUS_READY;
1788 
1789 <<done>>
1790    return l_status;
1791 
1792 exception
1793    when others then
1794       raise_others_error('get_return_status');
1795 end get_return_status;
1796 
1797 --------------------------------------------------------------------------------
1798 -- Prints information about the bugfix.
1799 --
1800 -- p_symbol - symbol
1801 -- p_bugfix_index - bugfix index
1802 --------------------------------------------------------------------------------
1803 procedure report_one_bugfix(p_symbol       in varchar2,
1804                             p_bugfix_index in binary_integer)
1805 is
1806    l_bugfix                  bugfix;
1807    l_replacement_bugfix_guid fnd_ums_bugfixes.bugfix_guid%type;
1808    l_replacement_bugfix      bugfix;
1809 begin
1810    l_bugfix := g_bugfixes(p_bugfix_index);
1811 
1812    -- write the symbol, bugfix id, application short name, and abstract
1813    append_to_report('');
1814    append_to_report(p_symbol || ' ' || l_bugfix.bugfix_id || ' ' ||
1815       l_bugfix.application_short_name || ': ' || l_bugfix.abstract);
1816 
1817    if (l_bugfix.release_status = RSTATUS_OBSOLETED) then
1818       append_to_report('   Action required: This patch is obsoleted, please use a replacement patch instead.');
1819 
1820       l_replacement_bugfix_guid := get_replacement_bugfix_guid(l_bugfix.bugfix_guid,
1821                                                                REPLACEMENT_LAST_NON_OBSOLETE);
1822 
1823       if (l_replacement_bugfix_guid is not null) then
1824          l_replacement_bugfix := get_bugfix(l_replacement_bugfix_guid);
1825 
1826          append_to_report('   Latest replacement: ' ||
1827             l_replacement_bugfix.bugfix_id || ' ' ||
1828             l_replacement_bugfix.application_short_name || ': ' ||
1829             l_replacement_bugfix.abstract);
1830       end if;
1831    end if;
1832 
1833    if (g_globals.debug_on) then
1834       append_to_report('   Release status: ' || l_bugfix.release_status);
1835       append_to_report('   Application status: ' || l_bugfix.application_status);
1836    end if;
1837 
1838 exception
1839    when others then
1840       raise_others_error('report_one_bugfix',
1841          p_symbol,
1842          g_bugfixes(p_bugfix_index).bug_number);
1843 end report_one_bugfix;
1844 
1845 --------------------------------------------------------------------------------
1846 -- Produces the report
1847 --------------------------------------------------------------------------------
1848 procedure produce_report
1849 is
1850    l_bugfix                     bugfix;
1851    l_symbol                     varchar2(10);
1852    l_symbol_obsoleted_used      boolean := false;
1853    l_symbol_missing_used        boolean := false;
1854    l_symbol_applied_used        boolean := false;
1855    l_symbol_no_information_used boolean := false;
1856    l_symbol_not_applied_used    boolean := false;
1857 begin
1858    -- Output the facts about analyzed bugfixes
1859 
1860    -- obsoleted top level bugfixes (UMS)
1861    -- required bugfixes (UMS)
1862    -- applied top level bugfixes (UMS or non-UMS)
1863    -- not applied, no information top level bugfixes (non-UMS)
1864    -- not applied top level bugfixes (UMS)
1865 
1866    for i in 0 .. g_globals.required_bugfix_count - 1 loop
1867 
1868       l_symbol := SYMBOL_MISSING;
1869       l_symbol_missing_used := true;
1870 
1871       report_one_bugfix(l_symbol, g_globals.required_bugfix_indexes(i));
1872    end loop;
1873 
1874    -- top level bugfixes (obsoleted, applied or not applied)
1875 
1876    for i in 0 .. g_globals.top_level_bugfix_count - 1 loop
1877       l_bugfix := g_bugfixes(i);
1878 
1879       if (not l_bugfix.required) then
1880 
1881          if (l_bugfix.release_status = RSTATUS_OBSOLETED) then
1882             -- flag the bugfix as obsoleted
1883 
1884             l_symbol := SYMBOL_OBSOLETED;
1885             l_symbol_obsoleted_used := true;
1886 
1887          elsif (l_bugfix.application_status = APP_STATUS_EXPLICITLY_APPLIED) then
1888             -- flag the bugfix as being already applied
1889 
1890             l_symbol := SYMBOL_APPLIED;
1891             l_symbol_applied_used := true;
1892 
1893          elsif (l_bugfix.patch_type = PATCH_TYPE_US_NON_UMS) then
1897             l_symbol_no_information_used := true;
1894             -- flag the bugfix as not having UMS metadata
1895 
1896             l_symbol := SYMBOL_NO_INFORMATION;
1898 
1899          else
1900             -- flag the bugfix as not applied
1901 
1902             l_symbol := SYMBOL_NOT_APPLIED;
1903             l_symbol_not_applied_used := true;
1904 
1905          end if;
1906 
1907          report_one_bugfix(l_symbol, l_bugfix.bugfix_index);
1908       end if;
1909    end loop;
1910 
1911    -- print the legend
1912 
1913    if (l_symbol_missing_used or
1914        l_symbol_obsoleted_used or
1915        l_symbol_applied_used or
1916        l_symbol_no_information_used or
1917        l_symbol_not_applied_used) then
1918 
1919       append_to_report('');
1920       append_to_report('Symbol Legend');
1921       append_to_report('-------------');
1922 
1923       if (l_symbol_missing_used) then
1924          append_to_report(SYMBOL_MISSING || ': Unapplied prerequisite patch.');
1925          append_to_report('   This prerequisite patch must be applied together with the current patch(es).');
1926          append_to_report('   Please merge this patch with the current patch(es) and apply them together.');
1927       end if;
1928 
1929       if (l_symbol_obsoleted_used) then
1930          append_to_report(SYMBOL_OBSOLETED || ': Obsoleted patch.');
1931          append_to_report('   An obsoleted patch cannot be applied.');
1932          append_to_report('   Please apply its replacement instead.');
1933       end if;
1934 
1935       if (l_symbol_applied_used) then
1936          append_to_report(SYMBOL_APPLIED || ': Applied patch.');
1937          append_to_report('   This patch is already applied and is about to be re-applied.');
1938       end if;
1939 
1940       if (l_symbol_no_information_used) then
1941          append_to_report(SYMBOL_NO_INFORMATION || ': Patch without prerequisite check information.');
1942          append_to_report('   This patch is about to be applied. However, it does not have a prerequisite');
1943          append_to_report('   check information file. Please check its README for any prerequisites.');
1944          append_to_report('   If there are any that have not been applied, please apply them first.');
1945       end if;
1946 
1947       if (l_symbol_not_applied_used) then
1948          append_to_report(SYMBOL_NOT_APPLIED || ': Patch with prerequisite check information.');
1949          append_to_report('   This patch is about to be applied.');
1950       end if;
1951 
1952       append_to_report('');
1953    end if;
1954 
1955 exception
1956    when others then
1957       raise_others_error('produce_report');
1958 end produce_report;
1959 
1960 --------------------------------------------------------------------------------
1961 -- Parses the comma-separated list of bug numbers and language codes
1962 -- and extracts them into an array.
1963 --
1964 -- p_bug_list - the comma-separated list of bug numbers and language codes
1965 -- x_bug_count - the number of bugs
1966 -- x_bug_array - the array of bug numbers and language codes
1967 --------------------------------------------------------------------------------
1968 procedure parse_bug_numbers(p_bug_list  in  varchar2,
1969                             x_bug_count out nocopy number,
1970                             x_bug_array out nocopy input_bug_array)
1971 is
1972    l_pos           number;
1973    l_bug_count     number;
1974    l_bug_list      varchar2(32000);
1975    l_vc2           varchar2(2000);
1976    l_bug_number    number;
1977    l_language_code varchar2(2000);
1978    l_error_message varchar2(2000);
1979 begin
1980    l_bug_count := 0;
1981    l_bug_list := Ltrim(Rtrim(p_bug_list,' '),' ');
1982 
1983    if (l_bug_list is null) then
1984       l_error_message := 'Empty bug number and language code list.';
1985       goto return_error;
1986    end if;
1987 
1988    --
1989    -- In case of trailing comma ',', adding space will force loop to go one
1990    -- more iteration and ':' is missing error will be displayed.
1991    --
1992    l_bug_list := l_bug_list || ' ';
1993 
1994    while l_bug_list is not null loop
1995       l_pos := instr(l_bug_list, ',');
1996 
1997       if (l_pos = 0) then
1998          l_pos := length(l_bug_list) + 1;
1999       end if;
2000 
2001       l_vc2 := substr(l_bug_list, 1, l_pos - 1);
2002       l_vc2 := ltrim(rtrim(l_vc2, ' '), ' ');
2003       l_bug_list := substr(l_bug_list, l_pos + 1);
2004 
2005       -- now we have '<bug_number>:<language_code>'
2006 
2007       l_pos := nvl(instr(l_vc2, ':'), 0);
2008 
2009       if (l_pos = 0) then
2010          l_error_message := 'Incorrect syntax in ''' || l_vc2 ||
2011             '''. '':'' is missing.';
2012          goto return_error;
2013       end if;
2014 
2015       -- get the bug_number.
2016 
2017       declare
2018          l_tmp varchar2(2000);
2019       begin
2020          l_tmp := substr(l_vc2, 1, l_pos - 1);
2021          l_bug_number := to_number(l_tmp);
2022          if l_bug_number is null then
2023             l_error_message := 'Incorrect syntax in ''' || l_vc2 ||
2024                '''. <bug_number> is missing.';
2025             goto return_error;
2026          end if;
2027       exception
2028          when others then
2029             l_error_message := 'Incorrect syntax in ''' || l_vc2 ||
2033 
2030                '''. <bug_number> is not a number.';
2031             goto return_error;
2032       end;
2034       -- get the language_code.
2035 
2036       begin
2037          l_language_code := substr(l_vc2, l_pos + 1);
2038          l_language_code := ltrim(l_language_code, ' ');
2039 
2040          if l_language_code is null then
2041             l_error_message := 'Incorrect syntax in ''' || l_vc2 ||
2042                '''. Language code is missing.';
2043             goto return_error;
2044          end if;
2045       end;
2046 
2047       x_bug_array(l_bug_count).bug_number := l_bug_number;
2048       x_bug_array(l_bug_count).language_code := l_language_code;
2049       l_bug_count := l_bug_count + 1;
2050    end loop;
2051 
2052    x_bug_count := l_bug_count;
2053    return;
2054 
2055 <<return_error>>
2056    raise_formatted_error(ERROR_UMS_INVALID_BUG_LIST,
2057       get_formatted_error('Syntax error in p_bug_numbers argument of UMS analysis engine call.',
2058          l_error_message,
2059          'The correct syntax is ' || '''<bug_number>:<language_code>[,<bug_number>:<language_code>]'''));
2060 exception
2061    when others then
2062       raise_others_error('parse_bug_numbers', p_bug_list);
2063 end parse_bug_numbers;
2064 
2065 --------------------------------------------------------------------------------
2066 -- Initializes the globals
2067 --
2068 -- p_appl_top_id - APPL_TOP id
2069 -- p_release_name - release name
2070 -- p_bug_numbers - bug numbers
2071 -- p_mode - engine mode
2072 --------------------------------------------------------------------------------
2073 procedure init_globals(p_appl_top_id  in  number,
2074                        p_release_name in  varchar2,
2075                        p_bug_numbers  in  varchar2,
2076                        p_mode         in  varchar2)
2077 is
2078 begin
2079    g_globals.appl_top_id := p_appl_top_id;
2080    g_globals.indent_level := 0;
2081    g_globals.top_level_bugfix_count := 0;
2082    g_globals.bugfix_count := 0;
2083    g_globals.required_bugfix_count := 0;
2084    g_globals.report_count := 1;
2085    g_globals.report(1) := '';
2086    g_globals.replacement_chain_tag_counter := 0;
2087    g_globals.obs_top_level_bugfix_exists := false;
2088    g_globals.status := null;
2089    g_globals.exception_depth := 0;
2090    g_globals.prereq_list := null;
2091 
2092    if (p_mode = MODE_NORMAL) then
2093       g_globals.debug_on := false;
2094    elsif (p_mode = MODE_DEBUG) then
2095       g_globals.debug_on := true;
2096    else
2097       raise_formatted_error(ERROR_UMS_INVALID_ENGINE_MODE,
2098          get_formatted_error('UMS analysis engine was not called properly.',
2099             p_mode || ' is not a valid UMS analysis engine mode.',
2100             'Valid modes are: ' || MODE_NORMAL || ', ' || MODE_DEBUG));
2101    end if;
2102 
2103    g_globals.engine_mode := p_mode;
2104 
2105    -- get APPL_TOP info, and report it
2106 
2107    declare
2108       l_appl_top_name varchar2(100);
2109       l_applications_system_name varchar2(100);
2110    begin
2111       begin
2112          select 'AFUMSAEB.pls : $Revision: 120.1 $ : init_globals' arcs_revision,
2113                 name, applications_system_name
2114            into g_arcs_revision,
2115                 l_appl_top_name, l_applications_system_name
2116            from ad_appl_tops
2117           where appl_top_id = p_appl_top_id;
2118       exception
2119          when no_data_found then
2120             if (p_appl_top_id = GLOBAL_APPL_TOP_ID) then
2121                l_appl_top_name := 'GLOBAL APPL_TOP';
2122             else
2123                l_appl_top_name := 'APPL_TOP_ID ' || p_appl_top_id || ' does not exist.';
2124             end if;
2125             l_applications_system_name := l_appl_top_name;
2126       end;
2127 
2128       append_to_report('Running UMS analysis engine with the following parameters:');
2129       append_to_report('');
2130       append_to_report('p_appl_top_id = ' || p_appl_top_id);
2131       append_to_report('   appl_top_name = ' || l_appl_top_name);
2132       append_to_report('   applications_system_name = ' || l_applications_system_name);
2133       append_to_report('p_release_name = ' || p_release_name);
2134       append_to_report('p_bug_numbers = ' || p_bug_numbers);
2135       append_to_report('p_mode = ' || p_mode);
2136    exception
2137       when no_data_found then
2138          raise_formatted_error(ERROR_UMS_INVALID_APPL_TOP_ID,
2139             get_formatted_error('UMS analysis engine was called with an invalid appl_top_id.',
2140                'The appl_top_id ' || p_appl_top_id || ' does not exist.'));
2141    end;
2142 
2143    -- parse the bug numbers and the language codes
2144 
2145    declare
2146       l_bugfix          bugfix;
2147 
2148       l_input_bug_count number;
2149       l_input_bug_array input_bug_array;
2150    begin
2151       parse_bug_numbers(p_bug_numbers, l_input_bug_count, l_input_bug_array);
2152 
2153       -- create top-level bugfixes in the global cache.
2154 
2155       for i in 0 .. l_input_bug_count - 1 loop
2156          l_bugfix := get_bugfix(p_release_name,
2157                                 l_input_bug_array(i).bug_number,
2158                                 l_input_bug_array(i).language_code);
2159 
2163             g_globals.obs_top_level_bugfix_exists := true;
2160          g_bugfixes(l_bugfix.bugfix_index).merged := true;
2161 
2162          if (l_bugfix.release_status = RSTATUS_OBSOLETED) then
2164          end if;
2165       end loop;
2166 
2167       g_globals.top_level_bugfix_count := g_globals.bugfix_count;
2168 
2169       for i in 0 .. g_globals.top_level_bugfix_count - 1 loop
2170          g_globals.top_level_bugfix_indexes(i) := i;
2171       end loop;
2172 
2173       if (g_globals.debug_on) then
2174          debug_array_to_report('Top Level Bugfixes');
2175       end if;
2176    end;
2177 
2178 exception
2179    when others then
2180       raise_others_error('init_globals',
2181          p_appl_top_id,
2182          p_release_name,
2183          p_bug_numbers,
2184          p_mode);
2185 end init_globals;
2186 
2187 --------------------------------------------------------------------------------
2188 procedure get_removable_obs_required(px_obs_required_bugfix_index in out nocopy binary_integer,
2189                                      px_replacement_bugfix_index  in out nocopy binary_integer)
2190 is
2191    l_bugfix                  bugfix;
2192    l_replacement_bugfix      bugfix;
2193    l_replacement_bugfix_guid fnd_ums_bugfixes.bugfix_guid%type;
2194 begin
2195    px_obs_required_bugfix_index := null;
2196    px_replacement_bugfix_index := null;
2197 
2198    -- Loop over required bugfixes
2199 
2200    for i in 0 .. g_globals.required_bugfix_count - 1 loop
2201 
2202       l_bugfix := g_bugfixes(g_globals.required_bugfix_indexes(i));
2203 
2204       if (l_bugfix.release_status = RSTATUS_OBSOLETED) then
2205 
2206          -- See if this bugfix has a first non obsolete bugfix
2207 
2208          l_replacement_bugfix_guid := get_replacement_bugfix_guid(l_bugfix.bugfix_guid,
2209                                                                   REPLACEMENT_FIRST_NON_OBSOLETE);
2210 
2211          if (l_replacement_bugfix_guid is not null) then
2212 
2213             l_replacement_bugfix := get_bugfix(l_replacement_bugfix_guid);
2214 
2215             -- This obsolete required bugfix is removable.
2216 
2217             px_obs_required_bugfix_index := l_bugfix.bugfix_index;
2218             px_replacement_bugfix_index := l_replacement_bugfix.bugfix_index;
2219 
2220             exit; -- from the required bugfix loop
2221          end if;
2222       end if;
2223    end loop;
2224 
2225 exception
2226    when others then
2227       raise_others_error('get_removable_obs_required');
2228 end get_removable_obs_required;
2229 
2230 --------------------------------------------------------------------------------
2231 procedure get_rid_of_obsolete_prereqs
2232 is
2233    l_obs_required_bugfix_index binary_integer;
2234    l_replacement_bugfix_index  binary_integer;
2235 begin
2236    if (g_globals.required_bugfix_count > 0) then
2237       -- Try to get rid of obsolete prereqs
2238 
2239       get_removable_obs_required(l_obs_required_bugfix_index,
2240                                  l_replacement_bugfix_index);
2241 
2242       if (l_obs_required_bugfix_index is not null) then
2243          if (g_globals.debug_on) then
2244             debug_to_report(' ');
2245             debug_to_report('Trying to get rid of obsolete prereqs:');
2246             debug_to_report('--------------------------------------------------');
2247          end if;
2248       end if;
2249 
2250       while (l_obs_required_bugfix_index is not null) loop
2251 
2252          -- We have a removable obsolete required bugfix
2253 
2254          if (g_globals.debug_on) then
2255             debug_to_report('Obsolete Prereq:' || g_bugfixes(l_obs_required_bugfix_index).bugfix_id);
2256             debug_to_report('Replacement    :' || g_bugfixes(l_replacement_bugfix_index).bugfix_id);
2257             debug_to_report(' ');
2258          end if;
2259 
2260          -- perform the dependency analysis
2261 
2262          check_bugfix_prereqs(l_replacement_bugfix_index);
2263 
2264          set_bugfix_required(l_replacement_bugfix_index, true);
2265 
2266          set_bugfix_required(l_obs_required_bugfix_index, false);
2267 
2268          if (g_globals.debug_on) then
2269             debug_array_to_report('Required Bugfixes');
2270          end if;
2271 
2272          get_removable_obs_required(l_obs_required_bugfix_index,
2273                                     l_replacement_bugfix_index);
2274       end loop;
2275    end if;
2276 exception
2277    when others then
2278       raise_others_error('get_rid_of_obsolete_prereqs');
2279 end get_rid_of_obsolete_prereqs;
2280 
2281 --------------------------------------------------------------------------------
2282 procedure check_top_level_bugfix_prereqs
2283 is
2284 begin
2285    if (g_globals.debug_on) then
2286       debug_to_report(' ');
2287       debug_to_report('Checking prereqs of top level bugfixes:');
2288       debug_to_report('--------------------------------------------------');
2289    end if;
2290 
2291    for i in 0 .. g_globals.top_level_bugfix_count - 1 loop
2292       check_bugfix_prereqs(g_globals.top_level_bugfix_indexes(i));
2293    end loop;
2294 
2295    if (g_globals.debug_on) then
2296       debug_array_to_report('Required Bugfixes');
2297    end if;
2298 exception
2299    when others then
2300       raise_others_error('check_top_level_bugfix_prereqs');
2301 end check_top_level_bugfix_prereqs;
2302 
2303 --------------------------------------------------------------------------------
2304 procedure analyze_dependencies(p_appl_top_id  in  number,
2305                                p_release_name in  varchar2,
2306                                p_bug_numbers  in  varchar2,
2307                                p_mode         in  varchar2,
2308                                x_status       out nocopy varchar2)
2309 is
2310 begin
2311    init_globals(p_appl_top_id, p_release_name, p_bug_numbers, p_mode);
2312 
2313    -- check for top-level obsoleted bugfixes
2314 
2315    if (g_globals.obs_top_level_bugfix_exists) then
2316       goto done;
2317    end if;
2318 
2319    -- check prereqs of top level bugfixes
2320 
2321    check_top_level_bugfix_prereqs();
2322 
2323    -- get rid of obsolete prereqs
2324 
2325    get_rid_of_obsolete_prereqs();
2326 
2327    -- post process required bugfixes
2328 
2329    post_process_required_bugfixes();
2330 
2331 <<done>>
2332    -- get the return status
2333 
2334    g_globals.status := get_return_status();
2335    g_globals.prereq_list := compute_prereq_list();
2336 
2337    -- produce the report
2338 
2339    produce_report();
2340 
2341    x_status := g_globals.status;
2342 exception
2343    when others then
2344       begin
2345          raise_others_error('analyze_dependencies',
2346             p_appl_top_id,
2347             p_release_name,
2348             p_bug_numbers,
2349             p_mode);
2350       exception
2351          when others then
2352             g_globals.status := STATUS_ERROR;
2353             x_status := g_globals.status;
2354             exception_to_report();
2355       end;
2356 end analyze_dependencies;
2357 
2358 --------------------------------------------------------------------------------
2359 function get_prereq_list
2360    return varchar2
2361 is
2362 begin
2363    if (not is_engine_called()) then
2364 
2365       raise_formatted_error(ERROR_UMS_ENGINE_NOT_CALLED,
2366          get_formatted_error('State error in get_prereq_list()',
2367             'analyze_dependencies() must be called first.'));
2368 
2369    elsif (g_globals.status in (STATUS_OBSOLETED, STATUS_ERROR)) then
2370 
2371       raise_formatted_error(ERROR_UMS_ILLEGAL_STATE,
2372          get_formatted_error('State error in get_prereq_list()',
2373             'Prereq list is not defined in ' || STATUS_OBSOLETED ||
2374             ' and ' || STATUS_ERROR || ' statuses.'));
2375 
2376    end if;
2377 
2378    return g_globals.prereq_list;
2379 exception
2380    when others then
2381       begin
2382          raise_others_error('get_prereq_list');
2383       exception
2384          when others then
2385             exception_to_report();
2386             raise;
2387       end;
2388 end get_prereq_list;
2389 
2390 --------------------------------------------------------------------------------
2391 function get_report_count return number
2392 is
2393 begin
2394    return g_globals.report_count;
2395 end get_report_count;
2396 
2397 --------------------------------------------------------------------------------
2398 function get_report(i in number) return varchar2
2399 is
2400 begin
2401    return g_globals.report(i);
2402 end get_report;
2403 
2404 begin
2405    NEWLINE := fnd_ums_loader.newline();
2406    g_globals.engine_mode := MODE_NOT_CALLED;
2407 end fnd_ums_analysis_engine;