1 package body FND_PROFILE_HIERARCHY_PKG as
2 /* $Header: AFPOMPHB.pls 120.1.12020000.2 2012/11/27 14:36:31 srinnakk ship $ */
3
4 /*
5 ** HIERARCHY_SWITCH_TYPE constants
6 */
7
8 TYPE_SECURITY_2_SERVRESP CONSTANT INTEGER := 1;
9 TYPE_SERVRESP_2_SECURITY CONSTANT INTEGER := 2;
10 TYPE_SERVER_2_SERVRESP CONSTANT INTEGER := 3;
11 TYPE_SERVRESP_2_SERVER CONSTANT INTEGER := 4;
12 TYPE_IGNORE CONSTANT INTEGER := -1;
13
14
15 /*
16 ** ROW TYPE
17 ROW_INSERTABLE CONSTANT INTEGER := 1;
18 ROW_UPDATABLE CONSTANT INTEGER := 2;
19 ROW_IGNORABLE CONSTANT INTEGER := 3;
20
21 */
22
23 /*
24 * Global types to hold the fetched values.
25 */
26
27 TYPE profile_value is TABLE OF FND_PROFILE_OPTION_VALUES.PROFILE_OPTION_VALUE%TYPE
28 INDEX BY BINARY_INTEGER;
29 TYPE profile_level is TABLE OF NUMBER
30 INDEX BY BINARY_INTEGER;
31
32 /*
33 ** Although similar definitions for CURSOR, One is used for present
34 ** hierarchy type and the other is used for target hierarchy.
35 ** Using the same cursor raises in a nested for loop, cursor_already_open.
36 */
37 CURSOR pov(appl_id number, prof_id number, lev_id number) IS
38 SELECT profile_option_value, level_value, level_value_application_id, level_value2
39 FROM fnd_profile_option_values
40 WHERE application_id = appl_id
41 AND profile_option_id = prof_id
42 AND level_id = lev_id;
43
44
45 /*
46 ** Collection to hold profile values at target hierarchy level
47 */
48 g_prof_val_4_update profile_value;
49
50 /*
51 ** Collection to hold profile values at source hierarchy level
52 */
53 g_prof_val_4_insert profile_value;
54
55 /*
56 ** Collection to hold profile level values at target hierarchy level
57 */
58 g_lev_val_4_update profile_level;
59
60 /*
61 ** Collection to hold profile level values at source hierarchy level
62 */
63 g_lev_val_4_insert profile_level;
64
65 /*
66 ** Collection to hold profile level application id values at target hierarchy level
67 */
68 g_lev_val_appl_4_update profile_level;
69
70 /*
71 ** Collection to hold profile level application id values at source hierarchy level
72 */
73 g_lev_val_appl_4_insert profile_level;
74
75 /*
76 ** define variable to hold the HIERARCHY_SWITCH_TYPE
77 */
78 g_type integer;
79
80 /*
81 ** 10003, if g_type = TYPE_SECURITY_2_SERVRESP
82 ** 10007, if g_type = TYPE_SERVRESP_2_SECURITY
83 ** 10005, if g_type = TYPE_SERVER_2_SERVRESP
84 ** 10007, if g_type = TYPE_SERVRESP_2_SERVER
85 **
86 */
87 g_from_lev_id number;
88
89 /*
90 ** 10007, if g_type = TYPE_SECURITY_2_SERVRESP
91 ** 10003, if g_type = TYPE_SERVRESP_2_SECURITY
92 ** 10007, if g_type = TYPE_SERVER_2_SERVRESP
93 ** 10005, if g_type = TYPE_SERVRESP_2_SERVER
94 **
95 */
96 g_to_lev_id number;
97
98
99 /*
100 * RESET - AOL Internal only.
101 * resets the global internal package variables.
102 */
103 procedure reset
104 is
105 begin
106 g_lev_val_4_update.delete;
107 g_lev_val_4_insert.delete;
108 g_lev_val_appl_4_update.delete;
109 g_lev_val_appl_4_insert.delete;
110 g_prof_val_4_update.delete;
111 g_prof_val_4_insert.delete;
112
113 g_type := null;
114 g_from_lev_id := null;
115 g_to_lev_id :=null;
116
117 end reset;
118
119
120 /*
121 ** SET_TYPE - AOL Internal only
122 **
123 ** Sets g_type, g_from_lev_id and g_to_lev_id values.
124 ** If the switch is ignorable, type is set to TYPE_IGNORABLE.
125 ** A hierarchy switch is ignorable if either source or destination
126 ** hierarchy types are not in (SERVRESP, SERVER, SECURITY) and one of
127 ** source or target hierarchy levels is not SERVRESP.
128 */
129 procedure set_type( x_profile_option_name varchar2,
130 x_hierarchy_type varchar2
131 )
132 is
133 l_db_hierarchy_type varchar2(8);
134 non_existant_profile exception;
135 begin
136 select hierarchy_type into l_db_hierarchy_type
137 from fnd_profile_options
138 where profile_option_name = x_profile_option_name;
139
140 if( upper(x_hierarchy_type) = 'SERVRESP') then
141 if ( upper(l_db_hierarchy_type) = 'SECURITY') then
142 g_type := TYPE_SECURITY_2_SERVRESP;
143 g_from_lev_id := 10003;
144 g_to_lev_id := 10007;
145 return;
146 end if;
147
148 if ( upper(l_db_hierarchy_type) = 'SERVER') then
149 g_type := TYPE_SERVER_2_SERVRESP;
150 g_from_lev_id := 10005;
151 g_to_lev_id := 10007;
152 return;
153 end if;
154 end if;
155
156 if( upper(l_db_hierarchy_type) = 'SERVRESP') then
157 if ( upper(x_hierarchy_type) = 'SECURITY') then
158 g_type := TYPE_SERVRESP_2_SECURITY;
159 g_from_lev_id := 10007;
160 g_to_lev_id := 10003;
161 return;
162 end if;
163 if ( upper(x_hierarchy_type) = 'SERVER') then
164 g_type := TYPE_SERVRESP_2_SERVER;
165 g_from_lev_id := 10007;
166 g_to_lev_id := 10005;
167 return;
168 end if;
169 end if;
170
171 g_type := TYPE_IGNORE;
172
173 exception
174 when no_data_found then
175 -- g_type := TYPE_IGNORE;
176 raise non_existant_profile;
177 end set_type;
178
179
180 /*
181 ** IS_FROM_ROW_VALID - AOL Internal only.
182 **
183 ** returns true if the row at source hierarchy level
184 ** has valid values at LEVEL_VALUE, LEVEL_VALUE_APPLICATION_ID and
185 ** LEVEL_VALUE2.
186 **/
187 function is_from_row_valid( x_lev_val number,
188 x_lev_val_appl number,
189 x_lev_val2 number
190 )
191 return boolean
192 is
193 begin
194 if( g_type = TYPE_SERVRESP_2_SECURITY) then
195 if(x_lev_val2 = -1)
196 then
197 return TRUE;
198 end if;
199 end if;
200
201 if( g_type = TYPE_SECURITY_2_SERVRESP) then
202 if(x_lev_val2 is null)
203 then
204 return TRUE;
205 end if;
206 end if;
207
208 if( g_type = TYPE_SERVRESP_2_SERVER) then
209 if( x_lev_val = -1) and ( x_lev_val_appl = -1)
210 then
211 return TRUE;
212 end if;
213 end if;
214 if( g_type = TYPE_SERVER_2_SERVRESP) then
215 if( x_lev_val2 is null ) and ( x_lev_val_appl is null )
216 then
217 return TRUE;
218 end if;
219 end if;
220
221 return FALSE;
222
223 end is_from_row_valid;
224
225 /*
226 ** IS_TO_ROW_VALID - AOL Internal only.
227 **
228 ** returns true if the row at target hierarchy level
229 ** has valid values at LEVEL_VALUE, LEVEL_VALUE_APPLICATION_ID and
230 ** LEVEL_VALUE2.
231 **/
232 function is_to_row_valid( x_lev_val number,
233 x_lev_val_appl number,
234 x_lev_val2 number
235 )
236 return boolean
237 is
238 begin
239
240 if( g_type = TYPE_SERVRESP_2_SECURITY) then
241 if (x_lev_val2 is null)
242 then
243 return TRUE;
244 end if;
245 end if;
246
247 if( g_type = TYPE_SECURITY_2_SERVRESP) then
248 if (x_lev_val2 = -1 )
249 then
250 return TRUE;
251 end if;
252 end if;
253
254 if( g_type = TYPE_SERVRESP_2_SERVER) then
255 if( x_lev_val2 is null and x_lev_val_appl is null)
256 then
257 return TRUE;
258 end if;
259 end if;
260 if( g_type = TYPE_SERVER_2_SERVRESP) then
261 if( x_lev_val = -1 and x_lev_val_appl = -1 )
262 then
263 return TRUE;
264 end if;
265 end if;
266
267 return FALSE;
268 end is_to_row_valid;
269
270 /*
271 ** IS_ROW_UPDATABLE - AOL Internal only.
272 **
273 ** returns true if the profile option value
274 ** at the target hierarchy level can be considered
275 ** updatable.
276 **/
277 function is_row_updatable( x_from_lev_val number,
278 x_to_lev_val number,
279 x_from_lev_val_appl number,
280 x_to_lev_val_appl number,
281 x_from_lev_val2 number,
282 x_to_lev_val2 number
283 )
284 return boolean
285 is
286 begin
287 if( is_to_row_valid ( x_to_lev_val,x_to_lev_val_appl, x_to_lev_val2) )then
288 if(g_type = TYPE_SERVRESP_2_SECURITY or g_type = TYPE_SECURITY_2_SERVRESP) then
289 if (x_from_lev_val = x_to_lev_val and x_from_lev_val_appl = x_to_lev_val_appl)
290 then
291 return TRUE;
292 end if;
293 end if;
294
295 if(g_type = TYPE_SERVRESP_2_SERVER ) then
296 if (x_from_lev_val2 = x_to_lev_val) then
297 return TRUE;
298 end if;
299 end if;
300
301 if(g_type = TYPE_SERVER_2_SERVRESP ) then
302 if (x_from_lev_val = x_to_lev_val2) then
303 return TRUE;
304 end if;
305 end if;
306 end if;
307
308 return FALSE;
309
310 end is_row_updatable;
311
312
313 /*
314 ** ADD_ROWS - AOL INTERNAL ONLY
315 ** The procedure separates insertable and updatable rows and
316 ** collects them into global collections.
317 */
318 procedure add_rows(x_profile_value_c in out nocopy profile_value ,
319 x_level_value_c in out nocopy profile_level,
320 x_level_val_appl_id_c in out nocopy profile_level,
321 x_profile_value varchar2,
322 x_level_value number,
323 x_level_value_appl_id number,
324 x_level_value2 number,
325 x_prof_ind number,
326 x_mode number)
327 is
328 begin
329 x_profile_value_c(x_prof_ind) := x_profile_value;
330
331 if( g_type = TYPE_SERVRESP_2_SECURITY or g_type = TYPE_SECURITY_2_SERVRESP) then
332 x_level_value_c(x_prof_ind) := x_level_value;
336 if ( g_type = TYPE_SERVRESP_2_SERVER ) then
333 x_level_val_appl_id_c(x_prof_ind):= x_level_value_appl_id;
334 end if;
335
337 if( x_mode = INSERT_ONLY) then
338 x_level_value_c(x_prof_ind) := x_level_value2;
339 x_level_val_appl_id_c(x_prof_ind):= null;
340 end if;
341
342 if( x_mode = UPDATE_ONLY) then
343 x_level_value_c(x_prof_ind) := x_level_value;
344 x_level_val_appl_id_c(x_prof_ind):= null;
345 end if;
346 end if;
347
348 if ( g_type = TYPE_SERVER_2_SERVRESP ) then
349 if( x_mode = INSERT_ONLY) then
350 x_level_value_c(x_prof_ind) := x_level_value;
351 x_level_val_appl_id_c(x_prof_ind):= -1;
352 end if;
353
354 if( x_mode = UPDATE_ONLY) then
355 x_level_value_c(x_prof_ind) := x_level_value2;
356 x_level_val_appl_id_c(x_prof_ind):= -1;
357 end if;
358 end if;
359 end add_rows;
360
361 /*
362 ** COLLECT_INSERTABLE_ROWS - AOL INTERNAL ONLY
363 ** The procedure collects insertable rows.
364 */
365 procedure collect_insertable_rows(x_appl_id number,
366 x_prof_id number
367 )
368 is
369 cursor pov_to(appl_id number, prof_id number, lev_id number) is
370 select profile_option_value, level_value, level_value_application_id, level_value2
371 from fnd_profile_option_values
372 where application_id = appl_id
373 and profile_option_id = prof_id
374 and level_id = lev_id;
375
376 l_row_type number;
377 l_prof_ind number:=0;
378 l_is_insertable boolean;
379 begin
380 FOR from_rec IN pov(x_appl_id, x_prof_id, g_from_lev_id) LOOP
381 if ( is_from_row_valid(
382 from_rec.level_value,
383 from_rec.level_value_application_id,
384 from_rec.level_value2
385 )
386 ) then
387 l_is_insertable := TRUE;
388 l_prof_ind := l_prof_ind +1;
389
390 FOR to_rec IN pov_to(x_appl_id, x_prof_id, g_to_lev_id) LOOP
391 if ( is_row_updatable (
392 from_rec.level_value,
393 to_rec.level_value,
394 from_rec.level_value_application_id,
395 to_rec.level_value_application_id,
396 from_rec.level_value2,
397 to_rec.level_value2
398 )
399 )
400 then
401 l_is_insertable := FALSE;
402 exit;
403 end if;
404
405 END LOOP;
406
407 if (l_is_insertable) then
408 add_rows(g_prof_val_4_insert,
409 g_lev_val_4_insert,
410 g_lev_val_appl_4_insert,
411 from_rec.profile_option_value,
412 from_rec.level_value,
413 from_rec.level_value_application_id,
414 from_rec.level_value2,
415 l_prof_ind,
416 INSERT_ONLY);
417 end if;
418 end if;
419 END LOOP;
420 end collect_insertable_rows;
421
422 /*
423 ** COLLECT_ALL_ROWS - AOL INTERNAL ONLY
424 ** The procedure collects insertable and updatable rows.
425 */
426 procedure collect_all_rows(x_appl_id number,
427 x_prof_id number
428 )
429 is
430 cursor pov_4_update(appl_id number, prof_id number, lev_id number) is
431 select profile_option_value, level_value, level_value_application_id, level_value2
432 from fnd_profile_option_values
433 where application_id = appl_id
434 and profile_option_id = prof_id
435 and level_id = lev_id
436 for update;
437
438 l_row_type number;
439 /* below two variables have been created to hold the index information
440 * for insert and update collections seperately, if the same index is used there is
441 * high possbility for the collection to have null elements in between */
442 l_prof_ind_upd number:=0; --- added for bug 15919372
443 l_prof_ind_ins number:=0; --- added for bug 15919372
444 l_is_insertable boolean;
445 begin
446 FOR from_rec IN pov(x_appl_id, x_prof_id, g_from_lev_id) LOOP
447
448 if ( is_from_row_valid(
449 from_rec.level_value,
450 from_rec.level_value_application_id,
451 from_rec.level_value2
452 )
453 )
454 then
455 l_is_insertable := TRUE;
456 /* l_prof_ind := l_prof_ind +1; commented for bug 15919372 */
457 FOR to_rec IN pov_4_update(x_appl_id, x_prof_id, g_to_lev_id) LOOP
458
462 from_rec.level_value_application_id,
459 if ( is_row_updatable (
460 from_rec.level_value,
461 to_rec.level_value,
463 to_rec.level_value_application_id,
464 from_rec.level_value2,
465 to_rec.level_value2
466 )
467 ) then
468 --- below line has been added for bug 15919372
469 l_prof_ind_upd := l_prof_ind_upd +1;
470 add_rows(g_prof_val_4_update,
471 g_lev_val_4_update,
472 g_lev_val_appl_4_update,
473 from_rec.profile_option_value,
474 to_rec.level_value,
475 to_rec.level_value_application_id,
476 to_rec.level_value2,
477 l_prof_ind_upd,
478 UPDATE_ONLY
479 );
480
481 l_is_insertable := FALSE;
482 exit;
483 end if;
484 END LOOP;
485
486 if (l_is_insertable) then
487 ---- below line has been added for bug 15919372
488 l_prof_ind_ins := l_prof_ind_ins +1;
489 add_rows(g_prof_val_4_insert,
490 g_lev_val_4_insert,
491 g_lev_val_appl_4_insert,
492 from_rec.profile_option_value,
493 from_rec.level_value,
494 from_rec.level_value_application_id,
495 from_rec.level_value2,
496 l_prof_ind_ins,
497 INSERT_ONLY);
498 end if;
499
500 end if;
501 END LOOP;
502 end collect_all_rows;
503
504 /*
505 ** The procedure carries a profile value and other who attributes when
506 ** its hierarchy type is changed. The source and target hierarchy
507 ** types should be from the set (SECURITY, SERVER, SERVRESP).
508 ** Any other hierarchy switch is ignored. The following hierarchy
509 ** switches are possible:
510 **
511 ** 1. SECURITY TO SERVRESP
512 ** In this switch all the profile values at level 10003 are considered
513 ** for carring forward to level 10007.
514 ** 2. SERVER TO SERVRESP
515 ** In this switch all the profile values at level 10005 are considered
516 ** for carring forward to level 10007.
517 ** 3. SERVRESP TO SECURITY
518 ** In this switch all the profile values at level 10007 are considered
519 ** for carring forward to level 10003.
520 ** 4. SERVRESP TO SERVER
521 ** In this switch all the profile values at level 10007 are considered
522 ** for carring forward to level 10005.
523 **
524 ** what profile values are carried is controlled by the parameter X_MODE.
525 ** profile option value rows can be either updatable rows or insertable rows.
526 **
527 ** when a profile has rows existing at the target hierarchy level, they are called
528 ** updatable rows. For example, when a profile hierarchy switch is from
529 ** SECURITY to SERVRESP, all rows in FND_PROFILE_OPTION_VALUES for this profile
530 ** are considered updatable if there exist a valid LEVEL_VALUE2 value at level 10007.
531 **
532 ** Insertable rows are all rows at source hierarchy level minus rows considered as
533 ** updatable.
534 **
535 ** 1. UPDATE_ONLY
536 ** In this mode profile option value and who columns of updatable rows are updated
537 ** from the similar rows at the source hierarchy level.
538 ** 2. INSERT_ONLY
539 ** In this mode profile option value and who columns of insertable rows are inserted
540 ** at the target hierarchy level. Updatable rows are untouched.
541 ** 3. INSERT_UPDATE
542 ** This mode is combination of both (1) and (2).
543 */
544 procedure carry_profile_values(
545 X_PROFILE_OPTION_NAME in VARCHAR2,
546 X_APPLICATION_ID in NUMBER,
547 X_PROFILE_OPTION_ID in NUMBER,
548 X_TO_HIERARCHY_TYPE in VARCHAR2,
549 X_LAST_UPDATE_DATE in DATE,
550 X_LAST_UPDATED_BY in NUMBER,
551 X_CREATION_DATE in DATE,
552 X_CREATED_BY in NUMBER,
553 X_LAST_UPDATE_LOGIN in NUMBER,
554 X_MODE in NUMBER default INSERT_UPDATE
555 )
556 is
557 begin
558 reset;
559 set_type(X_PROFILE_OPTION_NAME,X_TO_HIERARCHY_TYPE);
560
561 if (g_type = TYPE_IGNORE) then
562 return;
563 end if;
564
565 if(X_MODE = INSERT_UPDATE or X_MODE = UPDATE_ONLY) then
566 collect_all_rows(X_APPLICATION_ID,X_PROFILE_OPTION_ID);
567 end if;
568
569 if(X_MODE = INSERT_ONLY) then
570 collect_insertable_rows(X_APPLICATION_ID,X_PROFILE_OPTION_ID);
571 end if;
572
573 if(
574 (X_MODE = INSERT_UPDATE or X_MODE= UPDATE_ONLY)
575 and
576 (g_prof_val_4_update.first is not null)
577 ) then
578
579 FORALL rec in g_prof_val_4_update.first .. g_prof_val_4_update.last
580 update fnd_profile_option_values
581 set profile_option_value = g_prof_val_4_update(rec),
582 last_update_date = x_last_update_date,
583 last_update_login = x_last_update_login,
584 last_updated_by = x_last_updated_by
585 where level_id = g_to_lev_id
586 and application_id = x_application_id
587 and profile_option_id = x_profile_option_id
588 and level_value =
589 decode( g_type, TYPE_SERVER_2_SERVRESP, -1,g_lev_val_4_update(rec))
590 and nvl(level_value_application_id,-11111) =
591 nvl(decode(g_type, TYPE_SERVER_2_SERVRESP,-1,
592 TYPE_SERVRESP_2_SERVER, null,
593 g_lev_val_appl_4_update(rec)
594 ), -11111
595 )
596 and nvl(level_value2, -11111) =
597 nvl(decode(g_type,TYPE_SERVER_2_SERVRESP, g_lev_val_4_update(rec),
598 TYPE_SECURITY_2_SERVRESP, -1,
599 null
600 ), -11111
601 );
602
603 end if;
604
605 if(
606 (X_MODE = INSERT_UPDATE or X_MODE= INSERT_ONLY)
607 and
608 (g_prof_val_4_insert.first is not null)
609 )
610 then
611 FORALL rec in g_prof_val_4_insert.first .. g_prof_val_4_insert.last
612 insert into fnd_profile_option_values (
613 APPLICATION_ID,
614 PROFILE_OPTION_ID,
615 LEVEL_ID,
616 LEVEL_VALUE,
617 LAST_UPDATE_DATE,
618 LAST_UPDATED_BY,
619 CREATION_DATE,
620 CREATED_BY,
621 LAST_UPDATE_LOGIN,
622 PROFILE_OPTION_VALUE,
623 LEVEL_VALUE_APPLICATION_ID,
624 LEVEL_VALUE2
625 ) values (
626 X_APPLICATION_ID,
627 X_PROFILE_OPTION_ID,
628 g_to_lev_id,
629 decode(g_type,TYPE_SERVER_2_SERVRESP, -1,
630 g_lev_val_4_insert(rec)
631 ),
632 X_LAST_UPDATE_DATE,
633 X_LAST_UPDATED_BY,
634 X_CREATION_DATE,
635 X_CREATED_BY,
636 X_LAST_UPDATE_LOGIN,
637 g_prof_val_4_insert(rec),
638 decode(g_type,TYPE_SERVER_2_SERVRESP, -1,
639 TYPE_SERVRESP_2_SERVER,null,
640 g_lev_val_appl_4_insert(rec)
641 ),
642 decode(g_type,TYPE_SERVER_2_SERVRESP, g_lev_val_4_insert(rec),
643 TYPE_SECURITY_2_SERVRESP, -1,
644 null
645 )
646 );
647 end if;
648 end carry_profile_values;
649
650
651 /* ------------------ FOR DEBUGGING --------------------- */
652
653 procedure display ( value in out nocopy profile_value, name varchar2)
654 is
655 l_ind binary_integer;
656 begin
657 l_ind := value.first;
658 while (l_ind is not null)
659 loop
660 dbms_output.put_line(name||'['||l_ind||']:'|| value(l_ind));
661 l_ind:= value.next(l_ind);
662 end loop;
663
664 end;
665 procedure display ( value in out nocopy profile_level, name varchar2)
666 is
667 l_ind binary_integer;
668 begin
669 l_ind := value.first;
670 while (l_ind is not null)
671 loop
672 dbms_output.put_line(name||'['||l_ind||']:'|| value(l_ind));
673 l_ind:= value.next(l_ind);
674 end loop;
675
676 end;
677
678 end FND_PROFILE_HIERARCHY_PKG;