DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_FLEX_HIERARCHY_COMPILER

Source


1 PACKAGE BODY fnd_flex_hierarchy_compiler AS
2 /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
3 
4 
5 -- ======================================================================
6 --   Compiler Example
7 -- ======================================================================
8 --   North America Country, State, City Hierarchy.
9 --
10 --   FND_FLEX_VALUE_NORM_HIERARCHY
11 --   ===========================================
12 --   PARENT     CHILD_LOW  CHILD_HIGH  RANGE
13 --   ---------- ---------- ----------- ----------
14 --   CA         LA         LA          C
15 --   CA         SF         SF          C
16 --   CAN        Tor        Tor         C
17 --   US         Ch         Ch          C
18 --   NA         CAN        CAN         P
19 --   NA         US         US          P
20 --   US         CA         CA          P
21 --   US         NY         NY          P
22 --
23 --   FND_FLEX_VALUE_HIERARCHIES
24 --   ===========================================
25 --   PARENT  CHILD_LOW CHILD_HIGH COMMENT
26 --   ------- --------- ---------- ----------
27 --   CA      LA        LA         CA:LA-LA
28 --   CA      SF        SF         CA:SF-SF
29 --   CAN     Tor       Tor        CAN:Tor-Tor
30 --   US      Ch        Ch         US:Ch-Ch
31 --   NA      Tor       Tor        NA:CAN-CAN -> CAN:Tor-Tor
32 --   NA      Ch        Ch         NA:US-US -> US:Ch-Ch
33 --   NA      LA        LA         NA:US-US -> US:CA-CA -> CA:LA-LA
34 --   NA      SF        SF         NA:US-US -> US:CA-CA -> CA:SF-SF
35 --   US      LA        LA         US:CA-CA -> CA:LA-LA
36 --   US      SF        SF         US:CA-CA -> CA:SF-SF
37 --
38 --   FND_FLEX_VALUE_HIER_ALL
39 --   ===========================================
40 --   PARENT  CHILD_LOW CHILD_HIGH RANGE LEVEL COMMENT
41 --   ------- --------- ---------- ----- ----- ----------
42 --   CA      LA        LA         C     1     CA:LA-LA
43 --   CA      SF        SF         C     1     CA:SF-SF
44 --   CAN     Tor       Tor        C     1     CAN:Tor-Tor
45 --   US      Ch        Ch         C     1     US:Ch-Ch
46 --   NA      CAN       CAN        P     1     NA:CAN-CAN
47 --   NA      Tor       Tor        C     2     NA:CAN-CAN -> CAN:Tor-Tor
48 --   NA      US        US         P     1     NA:US-US
49 --   NA      Ch        Ch         C     2     NA:US-US -> US:Ch-Ch
50 --   NA      CA        CA         P     2     NA:US-US -> US:CA-CA
51 --   NA      LA        LA         C     3     NA:US-US -> US:CA-CA -> CA:LA-LA
52 --   NA      SF        SF         C     3     NA:US-US -> US:CA-CA -> CA:SF-SF
53 --   NA      NY        NY         P     2     NA:US-US -> US:NY-NY
54 --   US      CA        CA         P     1     US:CA-CA
55 --   US      LA        LA         C     2     US:CA-CA -> CA:LA-LA
56 --   US      SF        SF         C     2     US:CA-CA -> CA:SF-SF
57 --   US      NY        NY         P     1     US:NY-NY
58 --
59 -- ======================================================================
60 
61 -- ======================================================================
62 -- Package Globals.
63 -- ======================================================================
64 TYPE hierarchy_record IS RECORD
65   (parent_flex_value     fnd_flex_value_norm_hierarchy.parent_flex_value%TYPE,
66    child_flex_value_low  fnd_flex_value_norm_hierarchy.child_flex_value_low%TYPE,
67    child_flex_value_high fnd_flex_value_norm_hierarchy.child_flex_value_high%TYPE,
68    range_attribute       fnd_flex_value_norm_hierarchy.range_attribute%TYPE);
69 
70 TYPE hierarchy_array IS TABLE OF hierarchy_record INDEX BY BINARY_INTEGER;
71 
72 TYPE varchar2_array IS TABLE OF fnd_flex_value_norm_hierarchy.parent_flex_value%TYPE INDEX BY BINARY_INTEGER;
73 
74 --
75 -- Cycle Checker
76 --
77 g_parent_path_values      varchar2_array;
78 g_parent_path_value_count NUMBER;
79 
80 SUBTYPE vset_type IS fnd_flex_value_sets%ROWTYPE;
81 g_vset                   vset_type;
82 g_user_id                NUMBER := -1;
83 g_insert_count           NUMBER := 0;
84 g_commit_size            NUMBER := 500;
85 g_message_size           NUMBER := 1950;
86 g_debug_on               BOOLEAN := FALSE;
87 g_newline                VARCHAR2(10);
88 g_exception_depth        NUMBER := 0;
89 g_error_message          VARCHAR2(32000);
90 g_api_name               CONSTANT VARCHAR2(10) := 'HIER';
91 g_date_mask              CONSTANT VARCHAR2(100) := 'YYYY/MM/DD HH24:MI:SS';
92 
93 --
94 -- Error Codes
95 --
96 error_others                  NUMBER := -20100;
97 error_no_value_set            NUMBER := -20101;
98 error_delete_hierarchies      NUMBER := -20102;
99 error_cyclic_hierarchy        NUMBER := -20103;
100 error_unknown_range_attribute NUMBER := -20104;
101 error_update_hierarchies      NUMBER := -20105;
102 
103 
104 -- ======================================================================
105 -- PROCEDURE : set_debug
106 -- ======================================================================
107 -- Turns debug setting ON/OFF
108 --
109 PROCEDURE set_debug(p_debug_flag IN VARCHAR2)
110   IS
111 BEGIN
112    IF (Nvl(p_debug_flag, 'N') = 'Y') THEN
113       g_debug_on := TRUE;
114     ELSE
115       g_debug_on := FALSE;
116    END IF;
117 EXCEPTION
118    WHEN OTHERS THEN
119       g_debug_on := FALSE;
120 END set_debug;
121 
122 -- ======================================================================
123 -- PROCEDURE : debug
124 -- ======================================================================
125 -- Sends debug messages to Log file.
126 --
127 PROCEDURE debug(p_debug IN VARCHAR2)
128   IS
129 BEGIN
130    IF (g_debug_on) THEN
131       fnd_file.put_line(fnd_file.Log, p_debug);
132    END IF;
133 EXCEPTION
134    WHEN OTHERS THEN
135       NULL;
136 END debug;
137 
138 -- ======================================================================
139 -- PROCEDURE : init_parent_path
140 -- ======================================================================
141 -- Initializes the parent path array.
142 --
143 PROCEDURE init_parent_path
144   IS
145 BEGIN
146    g_parent_path_value_count := 0;
147 END init_parent_path;
148 
149 -- ======================================================================
150 -- PROCEDURE : add_to_parent_path
151 -- ======================================================================
152 -- Adds a parent value to the end of the parent path array.
153 --
154 PROCEDURE add_to_parent_path(p_parent_flex_value IN fnd_flex_value_norm_hierarchy.parent_flex_value%TYPE)
155   IS
156 BEGIN
157    g_parent_path_values(g_parent_path_value_count) := p_parent_flex_value;
158    g_parent_path_value_count := g_parent_path_value_count + 1;
159 END add_to_parent_path;
160 
161 -- ======================================================================
162 -- PROCEDURE : remove_from_parent_path
163 -- ======================================================================
164 -- Removes the last value from the end of the parent path array.
165 --
166 PROCEDURE remove_from_parent_path
167   IS
168 BEGIN
169    g_parent_path_value_count := g_parent_path_value_count - 1;
170 END remove_from_parent_path;
171 
172 -- ======================================================================
173 -- FUNCTION : exists_in_parent_path
174 -- ======================================================================
175 -- Checks if a parent value exists in the parent path array.
176 --
177 FUNCTION exists_in_parent_path(p_parent_flex_value IN fnd_flex_value_norm_hierarchy.parent_flex_value%TYPE)
178   RETURN BOOLEAN
179   IS
180      l_exists BOOLEAN;
181 BEGIN
182    l_exists := FALSE;
183    FOR i IN 0 .. g_parent_path_value_count - 1 LOOP
184       IF (g_parent_path_values(i) = p_parent_flex_value) THEN
185          l_exists := TRUE;
186          EXIT;
187       END IF;
188    END LOOP;
189 
190    RETURN l_exists;
191 END exists_in_parent_path;
192 
193 -- ======================================================================
194 -- FUNCTION : get_formatted_method_call
195 -- ======================================================================
196 -- Returns formatted method call
197 --
198 -- p_method - name of the method
199 -- p_arg1..5 - method arguments
200 --
201 -- return: formatted method call
202 --
203 FUNCTION get_formatted_method_call(p_method in varchar2,
204                                    p_arg1   in varchar2 default null,
205                                    p_arg2   in varchar2 default null,
206                                    p_arg3   in varchar2 default null,
207                                    p_arg4   in varchar2 default null,
208                                    p_arg5   in varchar2 default null)
209    return varchar2
210 is
211    l_method varchar2(32000);
212 begin
213    l_method := p_method || '(';
214 
215    if (p_arg1 is not null) then
216       l_method := l_method || p_arg1;
217    end if;
218 
219    if (p_arg2 is not null) then
220       l_method := l_method || ', ' || p_arg2;
221    end if;
222 
223    if (p_arg3 is not null) then
224       l_method := l_method || ', ' || p_arg3;
225    end if;
226 
227    if (p_arg4 is not null) then
228       l_method := l_method || ', ' || p_arg4;
229    end if;
230 
231    if (p_arg5 is not null) then
232       l_method := l_method || ', ' || p_arg5;
233    end if;
234 
235    l_method := l_method || ')';
236 
237    return l_method;
238 
239 exception
240    when others then
241       return p_method;
242 end get_formatted_method_call;
243 
244 -- ======================================================================
245 -- FUNCTION : get_formatted_lines
246 -- ======================================================================
247 -- Returns formatted error lines.
248 --
249 -- p_line0 - The first line that goes after ORA error number
250 -- p_line1..5 - optional lines to be indented
251 --
252 -- return: formatted error message
253 --
254 FUNCTION get_formatted_lines(p_line0 in varchar2,
255                              p_line1 in varchar2 default null,
256                              p_line2 in varchar2 default null,
257                              p_line3 in varchar2 default null,
258                              p_line4 in varchar2 default null,
259                              p_line5 in varchar2 default null)
260    return varchar2
261 is
262    l_error_text     varchar2(32000);
263    l_newline_indent varchar2(2000);
264 begin
265    l_newline_indent := g_newline || rpad(' ', 11, ' ');
266 
267    l_error_text := p_line0;
268 
269    if (p_line1 is not null) then
270       l_error_text := l_error_text || l_newline_indent || p_line1;
271    end if;
272 
273    if (p_line2 is not null) then
274       l_error_text := l_error_text || l_newline_indent || p_line2;
275    end if;
276 
277    if (p_line3 is not null) then
278       l_error_text := l_error_text || l_newline_indent || p_line3;
279    end if;
280 
281    if (p_line4 is not null) then
282       l_error_text := l_error_text || l_newline_indent || p_line4;
283    end if;
284 
285    if (p_line5 is not null) then
286       l_error_text := l_error_text || l_newline_indent || p_line5;
287    end if;
288 
289    return l_error_text;
290 
291 end get_formatted_lines;
292 
293 -- ======================================================================
294 -- PROCEDURE : raise_formatted_error
295 -- ======================================================================
296 -- Raises formatted application error.
297 --
298 -- p_error_code - error code
299 -- p_error_text - error text
300 --
301 PROCEDURE raise_formatted_error(p_error_code in number,
302                                 p_error_text in varchar2)
303 is
304    l_error_text varchar2(32000);
305 begin
306    l_error_text := p_error_text || g_newline || dbms_utility.format_error_stack();
307 
308    raise_application_error(p_error_code, l_error_text);
309 
310 exception
311    when others then
312       --
313       -- Store the root cause of the problem. This will be presented to
314       -- user as the main cause of the exception. Rest of the exception is
315       -- basically the call stack trace.
316       --
317       if (g_exception_depth = 0) then
318          g_error_message := dbms_utility.format_error_stack();
319       end if;
320 
321       g_exception_depth := g_exception_depth + 1;
322 
323       raise;
324 end raise_formatted_error;
325 
326 -- ======================================================================
327 -- PROCEDURE : raise_exception_error
328 -- ======================================================================
329 -- Raises exception by formatting the error lines.
330 --
331 -- p_error_code - error code
332 -- p_line0 - The first line that goes after ORA error number
333 -- p_line1..5 - optional lines to be indented
334 --
335 PROCEDURE raise_exception_error(p_error_code in number,
336                                 p_line0 in varchar2,
337                                 p_line1 in varchar2 default null,
338                                 p_line2 in varchar2 default null,
339                                 p_line3 in varchar2 default null,
340                                 p_line4 in varchar2 default null,
341                                 p_line5 in varchar2 default null)
342   IS
343      l_error_text VARCHAR2(32000);
344 BEGIN
345    l_error_text := get_formatted_lines(p_line0,
346                                        p_line1,
347                                        p_line2,
348                                        p_line3,
349                                        p_line4,
350                                        p_line5);
351 
352    raise_formatted_error(p_error_code, l_error_text);
353 
354    -- No exception handling here
355 END raise_exception_error;
356 
357 -- ======================================================================
358 -- PROCEDURE : raise_others_error
359 -- ======================================================================
360 -- Raises formatted error for 'when others then' block
361 --
362 -- p_method - name of the method
363 -- p_arg1..5 - method arguments
364 --
365 PROCEDURE raise_others_error(p_method in varchar2,
366                              p_arg1   in varchar2 default null,
367                              p_arg2   in varchar2 default null,
368                              p_arg3   in varchar2 default null,
369                              p_arg4   in varchar2 default null,
370                              p_arg5   in varchar2 default null)
371 is
372    l_error_text varchar2(32000);
373 begin
374    l_error_text := get_formatted_method_call(p_method,
375                                              p_arg1,
376                                              p_arg2,
377                                              p_arg3,
378                                              p_arg4,
379                                              p_arg5);
380 
381    l_error_text := l_error_text || ' raised exception.';
382 
383    raise_formatted_error(error_others, l_error_text);
384 
385    -- No exception handling here
386 end raise_others_error;
387 
388 -- ======================================================================
389 -- FUNCTION : get_vset
390 -- ======================================================================
391 -- Gets Value Set
392 --
393 PROCEDURE get_vset(p_flex_value_set    IN VARCHAR2,
394                    x_vset              OUT nocopy vset_type)
395   IS
396 BEGIN
397    --
398    -- Try it as FLEX_VALUE_SET_ID.
399    --
400    SELECT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
401      *
402      INTO x_vset
403      FROM fnd_flex_value_sets
404      WHERE flex_value_set_id = To_number(p_flex_value_set);
405 
406    RETURN;
407 
408 EXCEPTION
409    WHEN OTHERS THEN
410       --
411       -- ID didn't work, try it as FLEX_VALUE_SET_NAME.
412       --
413       BEGIN
414          SELECT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
415            *
416            INTO x_vset
417            FROM fnd_flex_value_sets
418            WHERE flex_value_set_name = p_flex_value_set;
419 
420          RETURN;
421 
422       EXCEPTION
423          WHEN OTHERS THEN
424             --
425             -- NAME didn't work too.
426             --
427             raise_exception_error(error_no_value_set,
428                                   'No data found in FND_FLEX_VALUE_SETS',
429                                   'for flex value set ' || p_flex_value_set);
430       END;
431 END get_vset;
432 
433 -- ======================================================================
434 -- PROCEDURE : compile_child
435 -- ======================================================================
436 -- Inserts the child range into the de-normalized hierarchy table.
437 --
438 PROCEDURE compile_child(p_root_parent_flex_value IN VARCHAR2,
439                         p_child_flex_value_low   IN VARCHAR2,
440                         p_child_flex_value_high  IN VARCHAR2)
441   IS
442 BEGIN
443    INSERT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
444      INTO fnd_flex_value_hierarchies
445      (flex_value_set_id, parent_flex_value,
446       child_flex_value_low, child_flex_value_high,
447       last_update_date, last_updated_by,
448       creation_date, created_by)
449      VALUES
450      (g_vset.flex_value_set_id*(-1), p_root_parent_flex_value,
451       p_child_flex_value_low, p_child_flex_value_high,
452       Sysdate, g_user_id,
453       Sysdate, g_user_id);
454 
455    g_insert_count := g_insert_count + 1;
456    IF (g_insert_count = g_commit_size) THEN
457       COMMIT;
458       g_insert_count := 0;
459    END IF;
460 EXCEPTION
461    WHEN OTHERS THEN
462       raise_others_error('compile_child',
463                          p_root_parent_flex_value,
464                          p_child_flex_value_low,
465                          p_child_flex_value_high);
466 END compile_child;
467 
468 -- ======================================================================
469 -- PROCEDURE : compile_parent
470 -- ======================================================================
471 -- Recursively compiles the parent ranges.
472 --
473 PROCEDURE compile_parent(p_root_parent_flex_value IN VARCHAR2,
474                          p_child_flex_value_low   IN VARCHAR2,
475                          p_child_flex_value_high  IN VARCHAR2,
476                          p_debug                  IN VARCHAR2)
477   IS
478      CURSOR norm_cur(p_child_flex_value_low  IN VARCHAR2,
479                      p_child_flex_value_high IN VARCHAR2) IS
480         SELECT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
481           parent_flex_value,
482           child_flex_value_low,
483           child_flex_value_high,
484           range_attribute
485           FROM fnd_flex_value_norm_hierarchy
486           WHERE flex_value_set_id = g_vset.flex_value_set_id
487           AND parent_flex_value >= p_child_flex_value_low
488           AND parent_flex_value <= p_child_flex_value_high
489           ORDER BY range_attribute, parent_flex_value,
490           child_flex_value_low, child_flex_value_high;
491 
492      l_debug           VARCHAR2(32000);
493 
494      l_hierarchies     hierarchy_array;
495      l_hierarchy_count BINARY_INTEGER;
496 BEGIN
497    l_hierarchy_count := 0;
498    FOR norm_rec IN norm_cur(p_child_flex_value_low,
499                             p_child_flex_value_high) LOOP
500       l_hierarchies(l_hierarchy_count).parent_flex_value     := norm_rec.parent_flex_value;
501       l_hierarchies(l_hierarchy_count).child_flex_value_low  := norm_rec.child_flex_value_low;
502       l_hierarchies(l_hierarchy_count).child_flex_value_high := norm_rec.child_flex_value_high;
503       l_hierarchies(l_hierarchy_count).range_attribute       := norm_rec.range_attribute;
504       l_hierarchy_count := l_hierarchy_count + 1;
505    END LOOP;
506 
507    FOR i IN 0 .. l_hierarchy_count - 1 LOOP
508       IF (g_debug_on) THEN
509          l_debug := (p_debug || ' -> ' ||
510                      l_hierarchies(i).range_attribute || ':' ||
511                      l_hierarchies(i).parent_flex_value || ':' ||
512                      l_hierarchies(i).child_flex_value_low || '-' ||
513                      l_hierarchies(i).child_flex_value_high);
514          debug(l_debug);
515       END IF;
516 
517       IF (l_hierarchies(i).range_attribute = 'C') THEN
518          compile_child(p_root_parent_flex_value,
519                        l_hierarchies(i).child_flex_value_low,
520                        l_hierarchies(i).child_flex_value_high);
521 
522        ELSIF (l_hierarchies(i).range_attribute = 'P') THEN
523          --
524          -- Cycle check
525          --
526          IF (exists_in_parent_path(l_hierarchies(i).parent_flex_value)) THEN
527             raise_exception_error(error_cyclic_hierarchy,
528                                   'Cyclic hierarchy detected.',
529                                   'Range Attribute  : ' || l_hierarchies(i).range_attribute,
530                                   'Parent Flex Value: ' || l_hierarchies(i).parent_flex_value,
531                                   'Low Child Value  : ' || l_hierarchies(i).child_flex_value_low,
532                                   'High Child Value : ' || l_hierarchies(i).child_flex_value_high);
533          END IF;
534 
535          --
536          -- Recursive call.
537          --
538          add_to_parent_path(l_hierarchies(i).parent_flex_value);
539          compile_parent(p_root_parent_flex_value,
540                         l_hierarchies(i).child_flex_value_low,
541                         l_hierarchies(i).child_flex_value_high,
542                         l_debug);
543          remove_from_parent_path();
544 
545        ELSE
546          raise_exception_error(error_unknown_range_attribute,
547                                'Unknown Range Attribute detected.',
548                                'Range Attribute  : ' || l_hierarchies(i).range_attribute,
549                                'Parent Flex Value: ' || l_hierarchies(i).parent_flex_value,
550                                'Low Child Value  : ' || l_hierarchies(i).child_flex_value_low,
551                                'High Child Value : ' || l_hierarchies(i).child_flex_value_high);
552       END IF;
553   END LOOP;
554 EXCEPTION
555    WHEN OTHERS THEN
556       raise_others_error('compile_parent',
557                          p_root_parent_flex_value,
558                          p_child_flex_value_low,
559                          p_child_flex_value_high);
560 END compile_parent;
561 
562 -- ======================================================================
563 -- PROCEDURE : compile_value_hierarchies
564 -- ======================================================================
565 -- Compiles the flex value hierarchies in FND_FLEX_VALUE_HIERARCHIES table.
566 --
567 PROCEDURE compile_value_hierarchies
568   IS
569      CURSOR main_norm_cur IS
570         SELECT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
571           parent_flex_value,
572           child_flex_value_low,
573           child_flex_value_high,
574           range_attribute
575           FROM fnd_flex_value_norm_hierarchy
576           WHERE flex_value_set_id = g_vset.flex_value_set_id
577           ORDER BY range_attribute, parent_flex_value,
578           child_flex_value_low, child_flex_value_high;
579 
580      l_debug           VARCHAR2(32000);
581 
582      l_hierarchies     hierarchy_array;
583      l_hierarchy_count BINARY_INTEGER;
584 BEGIN
585    g_insert_count := 0;
586    l_hierarchy_count := 0;
587    FOR main_norm_rec IN main_norm_cur LOOP
588       l_hierarchies(l_hierarchy_count).parent_flex_value     := main_norm_rec.parent_flex_value;
589       l_hierarchies(l_hierarchy_count).child_flex_value_low  := main_norm_rec.child_flex_value_low;
590       l_hierarchies(l_hierarchy_count).child_flex_value_high := main_norm_rec.child_flex_value_high;
591       l_hierarchies(l_hierarchy_count).range_attribute       := main_norm_rec.range_attribute;
592       l_hierarchy_count := l_hierarchy_count + 1;
593    END LOOP;
594 
595    --
596    -- Initialize the cycle checking logic
597    --
598    init_parent_path();
599 
600    FOR i IN 0 .. l_hierarchy_count - 1 LOOP
601       IF (g_debug_on) THEN
602          l_debug := (l_hierarchies(i).range_attribute || ':' ||
603                      l_hierarchies(i).parent_flex_value || ':' ||
604                      l_hierarchies(i).child_flex_value_low || '-' ||
605                      l_hierarchies(i).child_flex_value_high);
606          debug(l_debug);
607       END IF;
608 
609       IF (l_hierarchies(i).range_attribute = 'C') THEN
610          compile_child(l_hierarchies(i).parent_flex_value,
611                        l_hierarchies(i).child_flex_value_low,
612                        l_hierarchies(i).child_flex_value_high);
613 
614        ELSIF (l_hierarchies(i).range_attribute = 'P') THEN
615          add_to_parent_path(l_hierarchies(i).parent_flex_value);
616          compile_parent(l_hierarchies(i).parent_flex_value,
617                         l_hierarchies(i).child_flex_value_low,
618                         l_hierarchies(i).child_flex_value_high,
619                         l_debug);
620          remove_from_parent_path();
621 
622        ELSE
623          raise_exception_error(error_unknown_range_attribute,
624                                'Unknown Range Attribute detected.',
625                                'Range Attribute  : ' || l_hierarchies(i).range_attribute,
626                                'Parent Flex Value: ' || l_hierarchies(i).parent_flex_value,
627                                'Low Child Value  : ' || l_hierarchies(i).child_flex_value_low,
628                                'High Child Value : ' || l_hierarchies(i).child_flex_value_high);
629       END IF;
630    END LOOP;
631 
632    --
633    -- Commit the remaining rows.
634    --
635    IF (g_insert_count > 0) THEN
636       COMMIT;
637       g_insert_count := 0;
638    END IF;
639 
640 EXCEPTION
641    WHEN OTHERS THEN
642       --
643       -- In case of error, delete the inserted rows (kind of rollback).
644       --
645       BEGIN
646          DELETE /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
647            FROM fnd_flex_value_hierarchies
648            WHERE flex_value_set_id = g_vset.flex_value_set_id;
649          COMMIT;
650       EXCEPTION
651          WHEN OTHERS THEN
652             NULL;
653       END;
654 
655       raise_others_error('compile_value_hierarchies');
656 END compile_value_hierarchies;
657 
658 -- ======================================================================
659 -- PROCEDURE : compile_child_all
660 -- ======================================================================
661 -- Inserts the child range into the de-normalized hierarchy table.
662 --
663 PROCEDURE compile_child_all(p_root_parent_flex_value IN VARCHAR2,
664                             p_range_attribute        IN VARCHAR2,
665                             p_child_flex_value_low   IN VARCHAR2,
666                             p_child_flex_value_high  IN VARCHAR2,
667                             p_hierarchy_level        IN NUMBER)
668   IS
669 BEGIN
670    INSERT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
671      INTO fnd_flex_value_hier_all
672      (flex_value_set_id, parent_flex_value, range_attribute,
673       child_flex_value_low, child_flex_value_high, hierarchy_level,
674       last_update_date, last_updated_by,
675       creation_date, created_by)
676      VALUES
677      (g_vset.flex_value_set_id*(-1), p_root_parent_flex_value, p_range_attribute,
678       p_child_flex_value_low, p_child_flex_value_high, p_hierarchy_level,
679       Sysdate, g_user_id,
680       Sysdate, g_user_id);
681 
682    g_insert_count := g_insert_count + 1;
683    IF (g_insert_count = g_commit_size) THEN
684       COMMIT;
685       g_insert_count := 0;
686    END IF;
687 EXCEPTION
688    WHEN OTHERS THEN
689       raise_others_error('compile_child_all',
690                          p_root_parent_flex_value,
691                          p_range_attribute,
692                          p_child_flex_value_low,
693                          p_child_flex_value_high,
694                          p_hierarchy_level);
695 END compile_child_all;
696 
697 
698 -- ======================================================================
699 -- PROCEDURE : compile_parent_all
700 -- ======================================================================
701 -- Recursively compiles the parent ranges.
702 --
703 PROCEDURE compile_parent_all(p_root_parent_flex_value IN VARCHAR2,
704                              p_child_flex_value_low   IN VARCHAR2,
705                              p_child_flex_value_high  IN VARCHAR2,
706                              p_hierarchy_level        IN NUMBER)
707   IS
708      CURSOR norm_cur(p_child_flex_value_low  IN VARCHAR2,
709                      p_child_flex_value_high IN VARCHAR2) IS
710         SELECT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
711           parent_flex_value,
712           child_flex_value_low,
713           child_flex_value_high,
714           range_attribute
715           FROM fnd_flex_value_norm_hierarchy
716           WHERE flex_value_set_id = g_vset.flex_value_set_id
717           AND parent_flex_value >= p_child_flex_value_low
718           AND parent_flex_value <= p_child_flex_value_high
719           ORDER BY range_attribute, parent_flex_value,
720           child_flex_value_low, child_flex_value_high;
721 
722      l_hierarchies     hierarchy_array;
723      l_hierarchy_count BINARY_INTEGER;
724 BEGIN
725    l_hierarchy_count := 0;
726    FOR norm_rec IN norm_cur(p_child_flex_value_low,
727                             p_child_flex_value_high) LOOP
728       l_hierarchies(l_hierarchy_count).parent_flex_value     := norm_rec.parent_flex_value;
729       l_hierarchies(l_hierarchy_count).child_flex_value_low  := norm_rec.child_flex_value_low;
730       l_hierarchies(l_hierarchy_count).child_flex_value_high := norm_rec.child_flex_value_high;
731       l_hierarchies(l_hierarchy_count).range_attribute       := norm_rec.range_attribute;
732       l_hierarchy_count := l_hierarchy_count + 1;
733    END LOOP;
734 
735    FOR i IN 0 .. l_hierarchy_count - 1 LOOP
736       IF (l_hierarchies(i).range_attribute = 'C') THEN
737          compile_child_all(p_root_parent_flex_value,
738                            l_hierarchies(i).range_attribute,
739                            l_hierarchies(i).child_flex_value_low,
740                            l_hierarchies(i).child_flex_value_high,
741                            p_hierarchy_level + 1);
742 
743        ELSIF (l_hierarchies(i).range_attribute = 'P') THEN
744          compile_child_all(p_root_parent_flex_value,
745                            l_hierarchies(i).range_attribute,
746                            l_hierarchies(i).child_flex_value_low,
747                            l_hierarchies(i).child_flex_value_high,
748                            p_hierarchy_level + 1);
749 
750          --
751          -- Cycle check
752          --
753          IF (exists_in_parent_path(l_hierarchies(i).parent_flex_value)) THEN
754             raise_exception_error(error_cyclic_hierarchy,
755                                   'Cyclic hierarchy detected.',
756                                   'Range Attribute  : ' || l_hierarchies(i).range_attribute,
757                                   'Parent Flex Value: ' || l_hierarchies(i).parent_flex_value,
758                                   'Low Child Value  : ' || l_hierarchies(i).child_flex_value_low,
759                                   'High Child Value : ' || l_hierarchies(i).child_flex_value_high);
760          END IF;
761 
762          --
763          -- Recursive call.
764          --
765          add_to_parent_path(l_hierarchies(i).parent_flex_value);
766          compile_parent_all(p_root_parent_flex_value,
767                             l_hierarchies(i).child_flex_value_low,
768                             l_hierarchies(i).child_flex_value_high,
769                             p_hierarchy_level + 1);
770          remove_from_parent_path();
771 
772        ELSE
773          raise_exception_error(error_unknown_range_attribute,
774                                'Unknown Range Attribute detected.',
775                                'Range Attribute  : ' || l_hierarchies(i).range_attribute,
776                                'Parent Flex Value: ' || l_hierarchies(i).parent_flex_value,
777                                'Low Child Value  : ' || l_hierarchies(i).child_flex_value_low,
778                                'High Child Value : ' || l_hierarchies(i).child_flex_value_high);
779       END IF;
780   END LOOP;
781 EXCEPTION
782    WHEN OTHERS THEN
783       raise_others_error('compile_parent_all',
784                          p_root_parent_flex_value,
785                          p_child_flex_value_low,
786                          p_child_flex_value_high,
787                          p_hierarchy_level);
788 END compile_parent_all;
789 
790 -- ======================================================================
791 -- PROCEDURE : compile_value_hierarchies_all
792 -- ======================================================================
793 -- Compiles the flex value hierarchies in FND_FLEX_VALUE_HIER_ALL table.
794 --
795 PROCEDURE compile_value_hierarchies_all
796   IS
797      CURSOR main_norm_cur IS
798         SELECT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
799           parent_flex_value,
800           child_flex_value_low,
801           child_flex_value_high,
802           range_attribute
803           FROM fnd_flex_value_norm_hierarchy
804           WHERE flex_value_set_id = g_vset.flex_value_set_id
805           ORDER BY range_attribute, parent_flex_value,
806           child_flex_value_low, child_flex_value_high;
807 
808      l_hierarchies     hierarchy_array;
809      l_hierarchy_count BINARY_INTEGER;
810 BEGIN
811    g_insert_count := 0;
812 
813 
814    IF (g_vset.security_enabled_flag = 'H') THEN
815       l_hierarchy_count := 0;
816       FOR main_norm_rec IN main_norm_cur LOOP
817          l_hierarchies(l_hierarchy_count).parent_flex_value     := main_norm_rec.parent_flex_value;
818          l_hierarchies(l_hierarchy_count).child_flex_value_low  := main_norm_rec.child_flex_value_low;
819          l_hierarchies(l_hierarchy_count).child_flex_value_high := main_norm_rec.child_flex_value_high;
820          l_hierarchies(l_hierarchy_count).range_attribute       := main_norm_rec.range_attribute;
821          l_hierarchy_count := l_hierarchy_count + 1;
822       END LOOP;
823 
824       --
825       -- Initialize the cycle checking logic
826       --
827       init_parent_path();
828 
829       FOR i IN 0 .. l_hierarchy_count - 1 LOOP
830 
831          IF (l_hierarchies(i).range_attribute = 'C') THEN
832             compile_child_all(l_hierarchies(i).parent_flex_value,
833                               l_hierarchies(i).range_attribute,
834                               l_hierarchies(i).child_flex_value_low,
835                               l_hierarchies(i).child_flex_value_high,
836                               1);
837           ELSIF (l_hierarchies(i).range_attribute = 'P') THEN
838             compile_child_all(l_hierarchies(i).parent_flex_value,
839                               l_hierarchies(i).range_attribute,
840                               l_hierarchies(i).child_flex_value_low,
841                               l_hierarchies(i).child_flex_value_high,
842                               1);
843 
844             add_to_parent_path(l_hierarchies(i).parent_flex_value);
845             compile_parent_all(l_hierarchies(i).parent_flex_value,
846                                l_hierarchies(i).child_flex_value_low,
847                                l_hierarchies(i).child_flex_value_high,
848                                1);
849             remove_from_parent_path();
850 
851           ELSE
852             raise_exception_error(error_unknown_range_attribute,
853                                   'Unknown Range Attribute detected.',
854                                   'Range Attribute  : ' || l_hierarchies(i).range_attribute,
855                                   'Parent Flex Value: ' || l_hierarchies(i).parent_flex_value,
856                                   'Low Child Value  : ' || l_hierarchies(i).child_flex_value_low,
857                                   'High Child Value : ' || l_hierarchies(i).child_flex_value_high);
858          END IF;
859       END LOOP;
860    END IF;
861 
862    --
863    -- Commit the remaining rows.
864    --
865    IF (g_insert_count > 0) THEN
866       COMMIT;
867       g_insert_count := 0;
868    END IF;
869 EXCEPTION
870    WHEN OTHERS THEN
871       --
872       -- In case of error, delete the inserted rows (kind of rollback).
873       --
874       BEGIN
875          DELETE /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
876            FROM fnd_flex_value_hier_all
877            WHERE flex_value_set_id = g_vset.flex_value_set_id;
878          COMMIT;
879       EXCEPTION
880          WHEN OTHERS THEN
881             NULL;
882       END;
883 
884       raise_others_error('compile_value_hierarchies_all');
885 END compile_value_hierarchies_all;
886 
887 
888 PROCEDURE delete_value_hierarchies
889    --
890    -- Delete the old data.
891    --
892 IS
893    l_row_count NUMBER;
894    BEGIN
895     l_row_count := 1;
896     WHILE (l_row_count > 0) LOOP
897      DELETE /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
898         FROM fnd_flex_value_hierarchies
899         WHERE flex_value_set_id = g_vset.flex_value_set_id and
900         rownum < 1000;
901         l_row_count := SQL%rowcount;
902      COMMIT;
903    END LOOP;
904    EXCEPTION
905       WHEN OTHERS THEN
906          raise_exception_error(error_delete_hierarchies,
907               'Unable to delete data in FND_FLEX_VALUE_HIERARCHIES table.');
908 END delete_value_hierarchies;
909 
910 PROCEDURE delete_value_hierarchies_all
911    --
912    -- Delete the old data.
913    --
914 IS
915    l_row_count NUMBER;
916    BEGIN
917     l_row_count := 1;
918     WHILE (l_row_count > 0) LOOP
919      DELETE /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
920         FROM fnd_flex_value_hier_all
921         WHERE flex_value_set_id = g_vset.flex_value_set_id and
922         rownum < 1000;
923         l_row_count := SQL%rowcount;
924      COMMIT;
925    END LOOP;
926    EXCEPTION
927       WHEN OTHERS THEN
928          raise_exception_error(error_delete_hierarchies,
929              'Unable to delete data in FND_FLEX_VALUE_HIER_ALL table.');
930 END delete_value_hierarchies_all;
931 
932 
933 PROCEDURE delete_sec_rule_allowed_vals
934    --
935    -- Delete the old data.
936    --
937 IS
938    l_row_count NUMBER;
939    BEGIN
940     l_row_count := 1;
941     WHILE (l_row_count > 0) LOOP
942      DELETE /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
943         FROM fnd_flex_sec_rule_allowed_vals
944         WHERE flex_value_set_id = g_vset.flex_value_set_id and
945         rownum < 1000;
946         l_row_count := SQL%rowcount;
947      COMMIT;
948    END LOOP;
949    EXCEPTION
950       WHEN OTHERS THEN
951          raise_exception_error(error_delete_hierarchies,
952               'Unable to delete data in FND_FLEX_SEC_RULE_ALLOWED_VALS table.');
953 END delete_sec_rule_allowed_vals;
954 
955 
956 
957 
958 
959 PROCEDURE update_value_hierarchies
960    --
961    -- Update the newly compiled data with the vset id.
962    --
963 IS
964    l_row_count NUMBER;
965    BEGIN
966     l_row_count := 1;
967     WHILE (l_row_count > 0) LOOP
968      UPDATE /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
969         fnd_flex_value_hierarchies
970         SET flex_value_set_id = g_vset.flex_value_set_id
971         WHERE flex_value_set_id = g_vset.flex_value_set_id*(-1) and
972         rownum < 1000;
973         l_row_count := SQL%rowcount;
974      COMMIT;
975    END LOOP;
976    EXCEPTION
977       WHEN OTHERS THEN
978          raise_exception_error(error_update_hierarchies,
979               'Unable to update data in FND_FLEX_VALUE_HIERARCHIES table.');
980 END update_value_hierarchies;
981 
982 PROCEDURE update_value_hierarchies_all
983    --
984    -- Update the newly compiled data with the vset id.
985    --
986 IS
987    l_row_count NUMBER;
988    BEGIN
989     l_row_count := 1;
990     WHILE (l_row_count > 0) LOOP
991      UPDATE /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
992         fnd_flex_value_hier_all
993         SET flex_value_set_id=g_vset.flex_value_set_id
994         WHERE flex_value_set_id = g_vset.flex_value_set_id*(-1) and
995         rownum < 1000;
996         l_row_count := SQL%rowcount;
997      COMMIT;
998    END LOOP;
999    EXCEPTION
1000       WHEN OTHERS THEN
1001          raise_exception_error(error_update_hierarchies,
1002               'Unable to update data in FND_FLEX_VALUE_HIERARCHIES table.');
1003 END update_value_hierarchies_all;
1004 
1005 
1006 
1007 PROCEDURE update_sec_rule_allowed_vals
1008    --
1009    -- Update the newly compiled data with the vset id.
1010    --
1011 IS
1012    l_row_count NUMBER;
1013    BEGIN
1014     l_row_count := 1;
1015     WHILE (l_row_count > 0) LOOP
1016      UPDATE /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
1017         fnd_flex_sec_rule_allowed_vals
1018         SET flex_value_set_id=g_vset.flex_value_set_id
1019         WHERE flex_value_set_id = g_vset.flex_value_set_id*(-1) and
1020         rownum < 1000;
1021         l_row_count := SQL%rowcount;
1022      COMMIT;
1023    END LOOP;
1024    EXCEPTION
1025       WHEN OTHERS THEN
1026          raise_exception_error(error_update_hierarchies,
1027               'Unable to update data in FND_FLEX_VALUE_HIERARCHIES table.');
1028 END update_sec_rule_allowed_vals;
1029 
1030 
1031 PROCEDURE compile_sec_rule_allowed_vals
1032    --
1033    -- Insert all the valid values based on the security rules
1034    --
1035    -- In this new logic created for better performance
1036    -- Only Character and Number Format Types are supported for
1037    -- Hier security. So we only need to worry about Number
1038    -- and Char comparisons. Other Format Types are supported
1039    -- with old logic. It is not feasible to support all
1040    -- format types with new logic.
1041 IS
1042    BEGIN
1043 
1044   IF (g_vset.format_type ='N') THEN -- Number format type
1045      INSERT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
1046      into fnd_flex_sec_rule_allowed_vals
1047      (FLEX_VALUE_SET_ID,
1048       FLEX_VALUE_RULE_ID,
1049       FLEX_VALUE,
1050       LAST_UPDATE_DATE,
1051       LAST_UPDATED_BY,
1052       CREATION_DATE,
1053       CREATED_BY)
1054      SELECT
1055        FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID*(-1),
1056        RS.FLEX_VALUE_RULE_ID,
1057        FND_FLEX_VALUES_VL.FLEX_VALUE,
1058        SYSDATE, 0, sysdate, 0
1059        FROM FND_FLEX_VALUES_VL, FND_FLEX_VALUE_RULES RS
1060        WHERE
1061        FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id
1062        AND FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID = RS.FLEX_VALUE_SET_ID
1063        AND FND_FLEX_VALUES_VL.ENABLED_FLAG = 'Y'
1064        AND NOT EXISTS
1065        (SELECT NULL FROM FND_FLEX_VALUE_RULE_LINES L, FND_FLEX_VALUE_RULES R
1066         WHERE L.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id
1067         AND L.FLEX_VALUE_RULE_ID = R.FLEX_VALUE_RULE_ID
1068         AND R.FLEX_VALUE_RULE_ID=RS.FLEX_VALUE_RULE_ID
1069         AND L.INCLUDE_EXCLUDE_INDICATOR = 'E'
1070         AND  fnd_number.canonical_to_number(FND_FLEX_VALUES_VL.FLEX_VALUE)
1071         BETWEEN
1072              fnd_number.canonical_to_number(NVL(L.FLEX_VALUE_LOW, FND_FLEX_VALUES_VL.FLEX_VALUE))
1073         AND  fnd_number.canonical_to_number(NVL(L.FLEX_VALUE_HIGH, FND_FLEX_VALUES_VL.FLEX_VALUE))) AND
1074         NOT EXISTS (SELECT NULL FROM
1075           FND_FLEX_VALUE_HIER_ALL H,
1076           FND_FLEX_VALUE_RULE_LINES L,
1077           FND_FLEX_VALUE_RULES R
1078           WHERE
1079           L.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id AND
1080           H.FLEX_VALUE_SET_ID = L.FLEX_VALUE_SET_ID  AND
1081           L.FLEX_VALUE_RULE_ID = R.FLEX_VALUE_RULE_ID AND
1082           R.FLEX_VALUE_RULE_ID=RS.FLEX_VALUE_RULE_ID AND
1083           L.INCLUDE_EXCLUDE_INDICATOR = 'E' AND
1084           fnd_number.canonical_to_number(FND_FLEX_VALUES_VL.FLEX_VALUE)
1085           BETWEEN
1086           fnd_number.canonical_to_number(H.CHILD_FLEX_VALUE_LOW) AND
1087           fnd_number.canonical_to_number(H.CHILD_FLEX_VALUE_HIGH) AND
1088           fnd_number.canonical_to_number(H.PARENT_FLEX_VALUE)
1089           BETWEEN
1090           fnd_number.canonical_to_number(NVL(L.FLEX_VALUE_LOW, H.PARENT_FLEX_VALUE)) AND
1091           fnd_number.canonical_to_number(NVL(L.FLEX_VALUE_HIGH, H.PARENT_FLEX_VALUE))) AND
1092           (NOT EXISTS (SELECT NULL FROM FND_FLEX_VALUE_RULES R
1093           WHERE R.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id AND
1094           R.FLEX_VALUE_RULE_ID=RS.FLEX_VALUE_RULE_ID AND
1095           NOT EXISTS (SELECT NULL
1096           FROM FND_FLEX_VALUE_RULE_LINES L WHERE
1097           L.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id AND
1098           L.FLEX_VALUE_RULE_ID = R.FLEX_VALUE_RULE_ID AND
1099           L.INCLUDE_EXCLUDE_INDICATOR = 'I' AND
1100           fnd_number.canonical_to_number(FND_FLEX_VALUES_VL.FLEX_VALUE)
1101           BETWEEN
1102           fnd_number.canonical_to_number(NVL(L.FLEX_VALUE_LOW, FND_FLEX_VALUES_VL.FLEX_VALUE)) AND
1103           fnd_number.canonical_to_number(NVL(L.FLEX_VALUE_HIGH, FND_FLEX_VALUES_VL.FLEX_VALUE))))
1104          OR  NOT EXISTS
1105           (SELECT NULL FROM FND_FLEX_VALUE_RULES R
1106           WHERE R.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id AND
1107           R.FLEX_VALUE_RULE_ID=RS.FLEX_VALUE_RULE_ID AND
1108          NOT EXISTS (SELECT NULL FROM FND_FLEX_VALUE_HIER_ALL H, FND_FLEX_VALUE_RULE_LINES L
1109          WHERE H.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id  AND
1110          H.FLEX_VALUE_SET_ID = L.FLEX_VALUE_SET_ID AND
1111          L.FLEX_VALUE_RULE_ID = R.FLEX_VALUE_RULE_ID AND
1112          L.INCLUDE_EXCLUDE_INDICATOR = 'I' AND
1113          fnd_number.canonical_to_number(FND_FLEX_VALUES_VL.FLEX_VALUE) BETWEEN
1114          fnd_number.canonical_to_number(H.CHILD_FLEX_VALUE_LOW) AND
1115          fnd_number.canonical_to_number(H.CHILD_FLEX_VALUE_HIGH) AND
1116          fnd_number.canonical_to_number(H.PARENT_FLEX_VALUE) BETWEEN
1117          fnd_number.canonical_to_number(NVL(L.FLEX_VALUE_LOW, H.PARENT_FLEX_VALUE)) AND
1118          fnd_number.canonical_to_number(NVL(L.FLEX_VALUE_HIGH, H.PARENT_FLEX_VALUE)))))
1119          ORDER BY
1120          FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID,
1121          RS.FLEX_VALUE_RULE_ID,
1122          fnd_number.canonical_to_number(FND_FLEX_VALUES_VL.FLEX_VALUE);
1123 
1124     ELSE -- Character format type (DATE TIME are not supported)
1125 
1126      INSERT /* $Header: AFFFCHYB.pls 120.4 2011/11/08 19:05:50 hgeorgi ship $ */
1127      into fnd_flex_sec_rule_allowed_vals
1128      (FLEX_VALUE_SET_ID,
1129       FLEX_VALUE_RULE_ID,
1130       FLEX_VALUE,
1131       LAST_UPDATE_DATE,
1132       LAST_UPDATED_BY,
1133       CREATION_DATE,
1134       CREATED_BY)
1135      SELECT
1136        FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID*(-1),
1137        RS.FLEX_VALUE_RULE_ID,
1138        FND_FLEX_VALUES_VL.FLEX_VALUE,
1139        SYSDATE, 0, sysdate, 0
1140        FROM FND_FLEX_VALUES_VL, FND_FLEX_VALUE_RULES RS
1141        WHERE
1142        FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id
1143        AND FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID = RS.FLEX_VALUE_SET_ID
1144        AND FND_FLEX_VALUES_VL.ENABLED_FLAG = 'Y'
1145        AND NOT EXISTS
1146        (SELECT NULL FROM FND_FLEX_VALUE_RULE_LINES L, FND_FLEX_VALUE_RULES R
1147         WHERE L.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id
1148         AND L.FLEX_VALUE_RULE_ID = R.FLEX_VALUE_RULE_ID
1149         AND R.FLEX_VALUE_RULE_ID=RS.FLEX_VALUE_RULE_ID
1150         AND L.INCLUDE_EXCLUDE_INDICATOR = 'E'
1151         AND  FND_FLEX_VALUES_VL.FLEX_VALUE
1152         BETWEEN  NVL(L.FLEX_VALUE_LOW, FND_FLEX_VALUES_VL.FLEX_VALUE)
1153         AND  NVL(L.FLEX_VALUE_HIGH, FND_FLEX_VALUES_VL.FLEX_VALUE)) AND
1154         NOT EXISTS (SELECT NULL FROM
1155           FND_FLEX_VALUE_HIER_ALL H,
1156           FND_FLEX_VALUE_RULE_LINES L,
1157           FND_FLEX_VALUE_RULES R
1158           WHERE
1159           L.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id AND
1160           H.FLEX_VALUE_SET_ID = L.FLEX_VALUE_SET_ID  AND
1161           L.FLEX_VALUE_RULE_ID = R.FLEX_VALUE_RULE_ID AND
1162           R.FLEX_VALUE_RULE_ID=RS.FLEX_VALUE_RULE_ID AND
1163           L.INCLUDE_EXCLUDE_INDICATOR = 'E' AND
1164           FND_FLEX_VALUES_VL.FLEX_VALUE
1165           BETWEEN  H.CHILD_FLEX_VALUE_LOW AND  H.CHILD_FLEX_VALUE_HIGH AND
1166           H.PARENT_FLEX_VALUE
1167           BETWEEN  NVL(L.FLEX_VALUE_LOW, H.PARENT_FLEX_VALUE) AND
1168           NVL(L.FLEX_VALUE_HIGH, H.PARENT_FLEX_VALUE)) AND
1169           (NOT EXISTS (SELECT NULL FROM FND_FLEX_VALUE_RULES R
1170           WHERE R.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id AND
1171           R.FLEX_VALUE_RULE_ID=RS.FLEX_VALUE_RULE_ID AND
1172           NOT EXISTS (SELECT NULL
1173           FROM FND_FLEX_VALUE_RULE_LINES L WHERE
1174           L.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id AND
1175           L.FLEX_VALUE_RULE_ID = R.FLEX_VALUE_RULE_ID AND
1176           L.INCLUDE_EXCLUDE_INDICATOR = 'I' AND
1177           FND_FLEX_VALUES_VL.FLEX_VALUE BETWEEN  NVL(L.FLEX_VALUE_LOW,
1178           FND_FLEX_VALUES_VL.FLEX_VALUE)
1179               AND NVL(L.FLEX_VALUE_HIGH, FND_FLEX_VALUES_VL.FLEX_VALUE)))
1180          OR  NOT EXISTS
1181           (SELECT NULL FROM FND_FLEX_VALUE_RULES R
1182           WHERE R.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id AND
1183           R.FLEX_VALUE_RULE_ID=RS.FLEX_VALUE_RULE_ID AND
1184          NOT EXISTS (SELECT NULL FROM FND_FLEX_VALUE_HIER_ALL H, FND_FLEX_VALUE_RULE_LINES L
1185          WHERE H.FLEX_VALUE_SET_ID = g_vset.flex_value_set_id  AND
1186          H.FLEX_VALUE_SET_ID = L.FLEX_VALUE_SET_ID AND
1187          L.FLEX_VALUE_RULE_ID = R.FLEX_VALUE_RULE_ID AND
1188          L.INCLUDE_EXCLUDE_INDICATOR = 'I' AND
1189          FND_FLEX_VALUES_VL.FLEX_VALUE BETWEEN  H.CHILD_FLEX_VALUE_LOW AND
1190        H.CHILD_FLEX_VALUE_HIGH
1191          AND H.PARENT_FLEX_VALUE BETWEEN  NVL(L.FLEX_VALUE_LOW,
1192        H.PARENT_FLEX_VALUE)
1193          AND NVL(L.FLEX_VALUE_HIGH, H.PARENT_FLEX_VALUE))))
1194          ORDER BY
1195          FND_FLEX_VALUES_VL.FLEX_VALUE_SET_ID,
1196          RS.FLEX_VALUE_RULE_ID,
1197          FND_FLEX_VALUES_VL.FLEX_VALUE;
1198 
1199    END IF;
1200 
1201    COMMIT;
1202    EXCEPTION
1203       WHEN OTHERS THEN
1204          raise_exception_error(error_update_hierarchies,
1208 
1205               'Unable to insert data in FND_FLEX_SEC_RULE_ALLOWED_VALS table.');
1206 END compile_sec_rule_allowed_vals;
1207 
1209 
1210 PROCEDURE request_lock(p_lock_name           IN VARCHAR2,
1211                        x_lock_handle         OUT nocopy VARCHAR2)
1212   IS
1213      l_lock_name   VARCHAR2(128);
1214      l_lock_handle VARCHAR2(128);
1215 BEGIN
1216    l_lock_name := 'FND.FLEX.VSET.HIERARCHY_COMPILER.' || p_lock_name;
1217    l_lock_handle := null;
1218    fnd_flex_server.request_lock(l_lock_name, l_lock_handle);
1219    x_lock_handle := l_lock_handle;
1220 END request_lock;
1221 
1222 
1223 PROCEDURE release_lock(p_lock_name           IN VARCHAR2,
1224                        p_lock_handle         IN VARCHAR2)
1225   IS
1226 BEGIN
1227    IF (p_lock_handle IS NOT NULL) THEN
1228       fnd_flex_server.release_lock(p_lock_name, p_lock_handle);
1229    END IF;
1230 END release_lock;
1231 
1232 
1233 PROCEDURE finish_hierarchy_processing
1234 IS
1235      l_lock_name   VARCHAR2(128);
1236      l_lock_handle VARCHAR2(128);
1237   BEGIN
1238 
1239      /*
1240       This lock is to stop value validation (per valueset)
1241       while data is being processed. We do not want to
1242       allow values to be validated from a FF or
1243       anyother place until the values are processed.
1244      */
1245      l_lock_name := g_vset.flex_value_set_name;
1246      request_lock(l_lock_name, l_lock_handle);
1247 
1248      delete_value_hierarchies();
1249      update_value_hierarchies();
1250      delete_value_hierarchies_all();
1251      update_value_hierarchies_all();
1252 
1253      delete_sec_rule_allowed_vals();
1254      update_sec_rule_allowed_vals();
1255 
1256      /*
1257       Release the lock once the process of normalizing
1258       the valuset data is complete.
1259      */
1260      release_lock(l_lock_name, l_lock_handle);
1261 
1262      COMMIT;
1263 
1264 END finish_hierarchy_processing;
1265 
1266 -- ======================================================================
1267 -- PROCEDURE : compile_hierarchy
1268 -- ======================================================================
1269 -- Compiles the flex value hierarchy.
1270 --
1271 PROCEDURE compile_hierarchy(p_flex_value_set IN VARCHAR2,
1272                             p_debug_flag     IN VARCHAR2 DEFAULT 'N',
1273                             x_result         OUT nocopy VARCHAR2,
1274                             x_message        OUT nocopy VARCHAR2)
1275   IS
1276      l_message     VARCHAR2(32000) := NULL;
1277      l_bes_message VARCHAR2(32000) := NULL;
1278      l_lock_name   VARCHAR2(128);
1279      l_lock_handle VARCHAR2(128);
1280 BEGIN
1281    --
1282    -- Set the debug flag
1283    --
1284    set_debug(p_debug_flag);
1285 
1286    --
1287    -- Set the global USER_ID variable.
1288    --
1289    BEGIN
1290       g_user_id := fnd_global.user_id;
1291    EXCEPTION
1292       WHEN OTHERS THEN
1293          g_user_id := -1;
1294    END;
1295 
1296    --
1297    -- Set the global g_vset variable.
1298    --
1299    get_vset(p_flex_value_set, g_vset);
1300 
1301    --
1302    -- Debug
1303    --
1304    IF (g_debug_on) THEN
1305       debug('Compiling Hierarchy for Value Set');
1306       debug('         Name : ' || g_vset.flex_value_set_name);
1307       debug('           Id : ' || g_vset.flex_value_set_id);
1308       debug('Security Flag : ' || g_vset.security_enabled_flag);
1309       debug(' ');
1310       debug('Flattened hierarchies : ');
1311       debug(Rpad('=', 80, '='));
1312    END IF;
1313 
1314    /*
1315       Request a lock at the beginning of this program so that no
1316       other instance of this program (updating the same valueset)
1317       can overwrite each other. Since the lock_name includes the
1318       valuset name, only other program instances updating the same
1319       valueset will be locked out. If another pogram instance is
1320       updating a different valueset, then there is no problem.
1321    */
1322    l_lock_name := 'FNDFFCHY.' || g_vset.flex_value_set_name;
1323    request_lock(l_lock_name, l_lock_handle);
1324 
1325    --
1326    -- Compile semi-denormalized hierarchies.
1327    --
1328    compile_value_hierarchies();
1329 
1330    --
1331    -- Compile fully denormalized hierarchies.
1332    --
1333    compile_value_hierarchies_all();
1334 
1335    --
1336    -- Compile all valid values based on hier security rules.
1337    --
1338    -- This new function compile_sec_rule_allowed_vals()
1339    -- was created for better performance.
1340    -- Only Char and Number Format Types are supported for
1341    -- Independent and Table Validatin Types.
1342    -- Date/Time are rarely used if ever.
1343      IF ((g_vset.security_enabled_flag = 'H') AND
1344          (g_vset.validation_type = 'I' OR g_vset.validation_type = 'F' ) AND
1345          (g_vset.format_type = 'C' OR g_vset.format_type = 'N')) THEN
1346         compile_sec_rule_allowed_vals();
1347      END IF;
1348 
1349    /******************************************************************
1350     Bug 3947152 The code was deleting all the hierarchy rules and then
1351     reinserting them in a normalized state. Hierarchy value rules
1352     are checked by security. The problem is that when
1353     all the hier rules are deleted and before they are reinserted there
1354     is a time frame where there is a security breach. Values that
1355     should be secured, will not be sec in that time frame. We recoded
1356     the logic so that we first insert the hierachy rules with a
1357     vsetid*(-1). Once done with the insert we create a lock so
1358     that no one can access the data, and then we delete the rows
1362     lock is released. At this time the only code that is reading the
1359     with orig vsetid and then we update the vsetid*(-1) with the
1360     orig vsetid. After that is done, we release the lock. If another
1361     process wants to read the hier security data it cannot until the
1363     hier rules data is fnd_flex_server.check_value_security and
1364     this is called in FND_FLEX_SERVER1.check_security. In the function
1365     check_security() we check to see if a lock exists and if there is a
1366     lock we do not process until the lock is released meaning the data
1367     is now updated and correct.
1368    *******************************************************************/
1369    --
1370    -- Finish hierarchy processing.
1371    --
1372     finish_hierarchy_processing();
1373 
1374    --
1375    -- SUCCESS message.
1376    --
1377    BEGIN
1378       fnd_message.set_name('FND', 'FLEX-HIERARCHY COMP DONE');
1379       fnd_message.set_token('VSID', (To_char(g_vset.flex_value_set_id) ||
1380                                      '/''' ||
1381                                      g_vset.flex_value_set_name || ''''));
1382       l_message := fnd_message.get;
1383    EXCEPTION
1384       WHEN OTHERS THEN
1385          l_message := ('The value hierarchy associated with ' ||
1386                        'value set ' || g_vset.flex_value_set_id ||
1387                        '/''' || g_vset.flex_value_set_name ||
1388                        ''' has been compiled successfully.');
1389    END;
1390 
1391    -- Raise BES Event: oracle.apps.fnd.flex.vst.hierarchy.compiled
1392 
1393    DECLARE
1394       l_parameters wf_parameter_list_t := wf_parameter_list_t();
1395    BEGIN
1396       wf_event.addparametertolist(p_name          => 'FLEX_VALUE_SET_ID',
1397                                   p_value         => g_vset.flex_value_set_id,
1398                                   p_parameterlist => l_parameters);
1399 
1400       wf_event.addparametertolist(p_name          => 'FLEX_VALUE_SET_NAME',
1401                                   p_value         => g_vset.flex_value_set_name,
1402                                   p_parameterlist => l_parameters);
1403 
1404       wf_event.raise(p_event_name => 'oracle.apps.fnd.flex.vst.hierarchy.compiled',
1405                      p_event_key  => g_vset.flex_value_set_name,
1406                      p_event_data => NULL,
1407                      p_parameters => l_parameters,
1408                      p_send_date  => Sysdate);
1409    EXCEPTION
1410       WHEN OTHERS THEN
1411          l_bes_message := 'Workflow: Business Event System raised exception.' ||
1412            g_newline || dbms_utility.format_error_stack();
1413    END;
1414 
1415    /*
1416     Release the lock of this program instance.
1417    */
1418    release_lock(l_lock_name, l_lock_handle);
1419 
1420    IF (l_bes_message IS NULL) THEN
1421       --
1422       -- Return SUCCESS
1423       --
1424       x_result := 'SUCCESS';
1425     ELSE
1426       --
1427       -- Return WARNING
1428       --
1429       x_result := 'WARNING';
1430       l_message := l_message || g_newline || g_newline || l_bes_message;
1431    END IF;
1432 
1433    x_message := Substr(l_message, 1, g_message_size);
1434 
1435 EXCEPTION
1436    WHEN OTHERS THEN
1437       BEGIN
1438 
1439          release_lock(l_lock_name, l_lock_handle);
1440 
1441          raise_others_error('compile_hierarchy',
1442                             p_flex_value_set,
1443                             p_debug_flag,
1444                             g_vset.flex_value_set_id,
1445                             g_vset.flex_value_set_name);
1446       EXCEPTION
1447          WHEN OTHERS THEN
1448             --
1449             -- Present the root cause of the problem
1450             --
1451             l_message := g_error_message || g_newline;
1452 
1453             --
1454             -- Add the error message stack
1455             --
1456             l_message := l_message || '----- Error Message Stack -----' || g_newline;
1457             l_message := l_message || dbms_utility.format_error_stack();
1458 
1459             --
1460             -- Return FAILURE
1461             --
1462             x_result := 'FAILURE';
1463             x_message := Substr(l_message, 1, g_message_size);
1464 
1465             RETURN;
1466       END;
1467 END compile_hierarchy;
1468 
1469 -- ======================================================================
1470 PROCEDURE compile_hierarchy(p_flex_value_set IN VARCHAR2,
1471                             x_result         OUT nocopy VARCHAR2,
1472                             x_message        OUT nocopy VARCHAR2)
1473   IS
1474 BEGIN
1475    compile_hierarchy(p_flex_value_set, 'N', x_result, x_message);
1476 END compile_hierarchy;
1477 
1478 
1479 PROCEDURE compile_hierarchy_all(p_flex_value_set IN VARCHAR2,
1480                                 p_debug_flag     IN VARCHAR2 DEFAULT 'N',
1481                                 x_result         OUT nocopy VARCHAR2,
1482                                 x_message        OUT nocopy VARCHAR2)
1483 
1484   IS
1485      ----------------------
1486      -- Local definitions -
1487      ----------------------
1488      l_value_set_id_sql    VARCHAR2(1000);
1489      l_value_set_id        NUMBER;
1490      l_result              VARCHAR2(10);
1491      l_message             VARCHAR2(2000);
1492      TYPE cursor_type IS   REF CURSOR;
1493      l_value_set_id_cur    cursor_type;
1494 
1495 
1496   BEGIN
1497 
1498    l_value_set_id_sql :=
1499    ('SELECT  /* Header: AFFFSV2B.pls 120.2.12000000.1 2007/01/18 13:18:43 appldev ship $ */ ' ||
1500     ' v.flex_value_set_id ' ||
1501     ' FROM  fnd_flex_value_sets v ' ||
1502     ' WHERE EXISTS ' ||
1503          ' (SELECT null ' ||
1504             ' FROM fnd_flex_value_norm_hierarchy h ' ||
1505            ' WHERE h.flex_value_set_id = v.flex_value_set_id)');
1506 
1507 
1508    OPEN l_value_set_id_cur FOR l_value_set_id_sql;
1509 
1510    LOOP
1511      FETCH l_value_set_id_cur INTO l_value_set_id;
1512      EXIT WHEN l_value_set_id_cur%NOTFOUND;
1513      compile_hierarchy(l_value_set_id, l_result, l_message);
1514 
1515      IF (l_result <> 'SUCCESS') THEN
1516          x_result := l_result;
1517          x_message := l_message;
1518          RETURN;
1519      END IF;
1520 
1521 
1522      --
1523      -- Debug
1524      --
1525      IF (g_debug_on) THEN
1526         debug('Compiling Hierarchy for Value Set');
1527         debug('         Name : ' || g_vset.flex_value_set_name);
1528         debug('           Id : ' || g_vset.flex_value_set_id);
1529         debug('Security Flag : ' || g_vset.security_enabled_flag);
1530         debug(' ');
1531         debug('Compile Value Set Hierarchy ALL : ');
1532         debug(Rpad('=', 80, '='));
1533      END IF;
1534 
1535    END LOOP;
1536 
1537    CLOSE l_value_set_id_cur;
1538 
1539 END compile_hierarchy_all;
1540 
1541 
1542 
1543 BEGIN
1544    g_newline := fnd_global.newline();
1545 END fnd_flex_hierarchy_compiler;