1 package body ff_exec as
2 /* $Header: ffexec.pkb 120.4.12000000.1 2007/01/17 17:44:40 appldev noship $ */
3 /*
4 NOTES
5 See ffrunf.lld for design documentation.
6 */
7 /*---------------------------------------------------------------------------*/
8 /*----------------------- constant definitions ------------------------------*/
9 /*---------------------------------------------------------------------------*/
10 /*
11 * Values that formula indicator variables can hold.
12 * The FF_WAS_DEFAULTED is to indicate when a database
13 * item was defaulted.
14 */
15 FF_NULL constant binary_integer := 0;
16 FF_NOT_NULL constant binary_integer := -1;
17 FF_WAS_DEFAULTED constant binary_integer := -2;
18
19 /*
20 * Cache size limits and default. No maximum specified, as
21 * should let the user find that!
22 */
23 FF_DFLT_CACHE_SIZE constant binary_integer := 300;
24 FF_MIN_CACHE_SIZE constant binary_integer := 5;
25 FF_MAX_CACHE_SIZE constant binary_integer := 5120;
26
27 /* increment value for database item cache values */
28 DBI_CACHE_INCR constant binary_integer := 64;
29
30 /* Invalid position in parameter table. */
31 INVALID_POS constant binary_integer := -1;
32
33 /* Action parameter to control formula execution mode. */
34 USE_FF_WRAPPER constant varchar2(128) := 'FF_USE_PLSQL_WRAPPER';
35
36 /* Action parameter to control formula cache size. */
37 FF_FMLA_CACHE_SIZE constant varchar2(128) := 'FF_PLSQL_CACHE_SIZE';
38
39 /* Number of bits in a context level mask. */
40 C_MASK_BITS constant binary_integer := 31;
41
42 /* Maximum number of active contexts in the cache. */
43 C_MAX_CONTEXTS constant binary_integer := 62;
44
45 /* Data types. */
46 C_DATE constant varchar2(10) := 'DATE';
47 C_NUMBER constant varchar2(10) := 'NUMBER';
48 C_TEXT constant varchar2(10) := 'TEXT';
49
50 --
51 -- Exception raised when the wrapper package is invalid or does not exist.
52 --
53 CANNOT_FIND_PROG_UNIT exception;
54 pragma exception_init(CANNOT_FIND_PROG_UNIT, -6508);
55 --
56 -- Exception raised when attempting to execute a formula compiled with an
57 -- out-of-date formula compiler (missing FORMULA interfaces).
58 --
59 BAD_PLSQL exception;
60 pragma exception_init(BAD_PLSQL, -6550);
61
62 /*---------------------------------------------------------------------------*/
63 /*------------- internal execution engine data structures -------------------*/
64 /*---------------------------------------------------------------------------*/
65 type t_binary_integer is table of binary_integer index by binary_integer;
66 type t_small_varchar2 is table of varchar2(10) index by binary_integer;
67 type t_big_varchar2 is table of varchar2(300) index by binary_integer;
68
69 /*
70 * This structure holds state information
71 * about the execution engine.
72 */
73 type exec_info_r is record
74 (
75 formula_id binary_integer, -- currently executing formula.
76 cache_slot binary_integer, -- cache slot in use.
77 effective_date date, -- effective date used for formula execution.
78
79 fmla_cache_size number, -- size of the formula cache.
80
81 /* following allow sanity checking */
82 input_rows number, -- rows in the inputs table.
83 output_rows number -- rows in the outputs table.
84
85 /* Use FF_WRAPPER_PKG instead of dynamic SQL. */
86 ,use_ff_wrapper boolean
87 );
88
89 --
90 -- Lookup type for mapping formula_id -> collection slot.
91 --
92 type fmla_lookup_t is table of binary_integer index by binary_integer;
93
94 /*-------------- internal execution cache data structures -------------------*/
95 /*
96 * The Fast Formula cache types.
97 * The cache consists of the following things:
98 * 1) A table of records that is essentially a combination of
99 * info from ff_formulas_f and ff_compiled_info_f.
100 * The formula cache size is limited, and is controlled by
101 * an internal variable. It defaults to FF_DFLT_CACHE_SIZE.
102 * In addition, a table of records that holds information derived
103 * from the ff_fdi_usages_f table.
104 * NOTE - performula, the in core fdiu is held, ordered by
105 * a combination of class and item name. i.e.
106 * U (Contexts)
107 * I (inputs), O (outputs), B (both),
108 * D (Database Items)
109 * Within this, the individual entries are ordered by item name.
110 * The reason for this is:
111 * a) Contexts must come before database items (to allow db item
112 * invalidation to work correctly).
113 * b) Make the ordering of the entries in the inputs and outputs
114 * tables predictable to the user, which may be of some benefit.
115 * 2) If the cache is full, then the cache behaves as a circular list.
116 * Formulas are evicted from the cache starting from the first cache
117 * entry and cycling around as necessary. The sticky flag is no
118 * longer used.
119 */
120 type fmla_info_r is record /* Formula info */
121 (
122 formula_id binary_integer,
123 effective_start_date date,
124 effective_end_date date,
125 formula_name varchar2(80),
126 package_name varchar2(80), -- pack.proc we execute.
127 first_fdiu binary_integer, -- first entry in fdiu for formula.
128 fdiu_count binary_integer, -- number of fdiu rows.
129 context_count binary_integer, -- how many contexts?
130 input_count binary_integer, -- how many inputs?
131 output_count binary_integer -- how many outputs?
132 );
133
134 --
135 -- The formula cache. Note: the size must match FF_MAX_CACHE_SIZE.
136 --
137 type fmla_info_t is varray(5120) of fmla_info_r;
138
139 type fdiu_info_r is record /* in core fdiu */
140 (
141 name varchar2(240), -- the 'real' name of the item.
142 varpos binary_integer, -- Position in variable table.
143 indpos binary_integer, -- Position in indicator table.
144 data_type varchar2(6), -- valid C_DATE, C_TEXT, C_NUMBER.
145 usage varchar2(1), -- 'I', 'O', 'B', 'U', 'D'.
146 context_sum1 binary_integer, -- for database items and contexts.
147 context_sum2 binary_integer, -- for database items and contexts.
148 context_id binary_integer, -- for database items and contexts.
149 route_id binary_integer -- for database items
150 );
151
152 type fdiu_info_t is table of fdiu_info_r index by binary_integer;
153
154 type free_chunk_t is table of binary_integer index by binary_integer;
155
156 /*
157 * The database item cache types.
158 * The database item cache consists of three tables that holds details
159 * about contexts and database items as appropriate. The details of
160 * these are:
161 * o A record and table type to hold the details of the contexts
162 * and database items in the cache. A separate table is used
163 * for contexts and database items. In the case of contexts,
164 * it is indexed directly by the context_id.
165 * o Since FF_DATABASE_ITEMS does not have a surrogate primary key,
166 * the formula compiler generates a hashed value, which is not
167 * guaranteed to be unique. Therefore, the database item cache
168 * is not indexed directly. Instead, there is a 'hash' data
169 * structure that points to the first possible entry in the
170 * database item cache table and the number of entries for this
171 * hash value. This allows 'row chaining' to be implemented.
172 * NOTES:
173 * The context_level field is either the context_level of the
174 * context or sum of context dependencies for database items.
175 * o The value field stores the current value for that item.
176 * If it is NULL, it indicates that the value is currently
177 * invalid. In the case of a database item, it means that we
178 * will need to fetch the value from the database.
179 */
180 type dbi_hash_r is record
181 (
182 first_entry binary_integer,
183 chain_count binary_integer
184 );
185
186 type dbi_hash_t is table of dbi_hash_r index by binary_integer;
187
188 type dbi_cache_r is record /* dbi and context info */
189 (
190 item_name ff_database_items.user_name%type,
191 context_level1 binary_integer,
192 context_level2 binary_integer,
193 data_type varchar2(10),
194 dvalue date,
195 nvalue number,
196 tvalue varchar2(255), -- matches ff_exec.FF_BIND_LEN
197 indicator binary_integer
198 );
199
200 type dbi_cache_t is table of dbi_cache_r index by binary_integer;
201 type ctx_cache_t is table of dbi_cache_r index by binary_integer;
202
203 /*
204 * Data structures for holding dynamic context level sums for routes.
205 */
206 type context_sums_r is record
207 (
208 context_sum1 binary_integer,
209 context_sum2 binary_integer
210 );
211
212 type route_ctx_sums_t is table of context_sums_r index by binary_integer;
213
214 /*---------------------------------------------------------------------------*/
215 /*----------------------- execution engine globals --------------------------*/
216 /*---------------------------------------------------------------------------*/
217 g_decpoint varchar2(100); -- Decimal point character for number/string conversion.
218 g_exec_info exec_info_r;
219 g_inited boolean := false; -- Cache initialised.
220 g_fmla_lookups fmla_lookup_t; -- Lookup table for formula information table.
221 g_fmla_info fmla_info_t; -- formula information.
222 g_lru_slot binary_integer; -- Least-Recently-Used formula slot.
223 g_fdiu_info fdiu_info_t; -- in core fdiu information.
224 g_free_fdiu free_chunk_t; -- Table of free FDIU chunks.
225 g_hash_info dbi_hash_t; -- Hash table for database item cache entries.
226 g_dbi_info dbi_cache_t; -- database item cache entries.
227 g_ctx_info dbi_cache_t; -- context entries.
228
229 --
230 -- g_ctx_levels1 and g_ctx_levels2 are allocated context levels.
231 -- g_route_ctx_sums caches the context levels for each route.
232 --
233 g_route_ctx_sums route_ctx_sums_t;
234 g_ctx_levels1 binary_integer := 0;
235 g_ctx_levels2 binary_integer := 0;
236
237 -- The next value for entry in database item cache table.
238 g_next_dbi_index binary_integer := 1;
239 /*---------------------------------------------------------------------------*/
240 /*------------------ local functions and procedures -------------------------*/
241 /*---------------------------------------------------------------------------*/
242
243 procedure set_use_ff_wrapper is
244 l_pap_found boolean;
245 l_pap_value varchar2(2000);
246 begin
247 --
248 -- Look for configuration information in PAY_ACTION_PARAMETERS.
249 --
250 pay_core_utils.get_action_parameter
251 (p_para_name => USE_FF_WRAPPER
252 ,p_para_value => l_pap_value
253 ,p_found => l_pap_found
254 );
255 --
256 g_exec_info.use_ff_wrapper := not l_pap_found or upper(l_pap_value) <> 'N';
257 end set_use_ff_wrapper;
258
259 procedure set_cache_size is
260 l_pap_found boolean;
261 l_pap_value varchar2(2000);
262 begin
263 --
264 -- Look for configuration information in PAY_ACTION_PARAMETERS.
265 --
266 begin
267 pay_core_utils.get_action_parameter
268 (p_para_name => FF_FMLA_CACHE_SIZE
269 ,p_para_value => l_pap_value
270 ,p_found => l_pap_found
271 );
272 if l_pap_found then
273 g_exec_info.fmla_cache_size := trunc(to_number(l_pap_value));
274 else
275 g_exec_info.fmla_cache_size := null;
276 end if;
277 exception
278 when others then
279 g_exec_info.fmla_cache_size := null;
280 end;
281
282 if g_exec_info.fmla_cache_size is null then
283 g_exec_info.fmla_cache_size := FF_DFLT_CACHE_SIZE;
284 elsif g_exec_info.fmla_cache_size < FF_MIN_CACHE_SIZE then
285 g_exec_info.fmla_cache_size := FF_MIN_CACHE_SIZE;
286 elsif g_exec_info.fmla_cache_size > FF_MAX_CACHE_SIZE then
287 g_exec_info.fmla_cache_size := FF_MAX_CACHE_SIZE;
288 end if;
289 end set_cache_size;
290
291 /*
292 * Checks if the FF_DEBUG profile has been set, and if so,
293 * whether any of the PLSQL execution engine debug settings
294 * should be enabled.
295 */
296 procedure check_profile_debug is
297 l_value varchar2(300);
298 l_exec_debug boolean := FALSE;
299 l_routing boolean := FALSE;
300 l_ff_debug boolean := FALSE;
301 l_ff_cache boolean := FALSE;
302 l_dbi_cache boolean := FALSE;
303 l_mru boolean := FALSE;
304 l_io boolean := FALSE;
305 l_char varchar2(1);
306 l_debug_level binary_integer := 0;
307 begin
308 -- Look for setting of FF_DEBUG profile.
309 fnd_profile.get('FF_DEBUG', l_value);
310
311 if(l_value is null) then
312 return;
313 end if;
314
315 -- Debug setting is possible, process which ones.
316 for l_pos in 1..length(l_value) loop
317 l_char := substr(l_value, l_pos, 1); -- get a single character.
318
319 if(l_char = 'X' or l_char = 'x') then
320 l_exec_debug := TRUE;
321 elsif(l_char = 'R' or l_char = 'r') then
322 l_routing := TRUE;
323 elsif(l_char = 'F' or l_char = 'f') then
324 l_ff_debug := TRUE;
325 elsif(l_char = 'C' or l_char = 'c') then
326 l_ff_cache := TRUE;
327 elsif(l_char = 'D' or l_char = 'd') then
328 l_dbi_cache := TRUE;
329 elsif(l_char = 'M' or l_char = 'm') then
330 l_mru := TRUE;
331 elsif(l_char = 'I' or l_char = 'i') then
332 l_io := TRUE;
333 else
334 null; -- ignore spurious characters.
335 end if;
336
337 end loop;
338
339 -- Need to have general execution engine logging set
340 -- before we can use the other options.
341 if(l_exec_debug) then
342 -- Set the appropriate flags.
343 if(l_routing) then
344 l_debug_level := l_debug_level + ff_utils.ROUTING;
345 end if;
346
347 if(l_ff_debug) then
348 l_debug_level := l_debug_level + ff_exec.FF_DBG;
349 end if;
350
351 if(l_ff_cache) then
352 l_debug_level := l_debug_level + ff_exec.FF_CACHE_DBG;
353 end if;
354
355 if(l_dbi_cache) then
356 l_debug_level := l_debug_level + ff_exec.DBI_CACHE_DBG;
357 end if;
358
359 if(l_mru) then
360 l_debug_level := l_debug_level + ff_exec.MRU_DBG;
361 end if;
362
363 if(l_io) then
364 l_debug_level := l_debug_level + ff_exec.IO_TABLE_DBG;
365 end if;
366
367 -- Set the global flag.
368 ff_utils.g_debug_level := l_debug_level;
369
370 end if;
371
372 end check_profile_debug;
373
374 /*
375 * Debug proceure to output information about formula
376 * cache contents for a specific formula.
377 * This procedure is overloaded.
378 */
379 procedure fmla_cache_debug
380 (
381 fid in binary_integer, -- formula_id
382 p_fmla_lookups in fmla_lookup_t,
383 p_fmla_info in fmla_info_t,
384 p_fdiu_info in fdiu_info_t
385 ) is
386
387 name varchar2(240);
388 varpos varchar2(100);
389 indpos varchar2(100);
390 data_type varchar2(10);
391 usage varchar2(10);
392 class varchar2(10);
393 context_sum1 varchar2(30);
394 context_sum2 varchar2(30);
395 context_id varchar2(10);
396 first binary_integer;
397 last binary_integer;
398 i binary_integer;
399 fmla_info fmla_info_r;
400 fdiu_info fdiu_info_r;
401
402 begin
403 -- Check the debug flag settting.
404 if(ff_utils.g_debug_level is null or ff_utils.g_debug_level = 0) then
405 return;
406 end if;
407
408 if(bitand(ff_utils.g_debug_level, ff_exec.FF_CACHE_DBG) <> 0) then
409 -- Debug level set correctly, output debug information for
410 -- specific formula.
411
412 hr_utility.trace('');
413 hr_utility.trace('FMLA CACHE info for formula_id ' || fid);
414 hr_utility.trace('--------------------------------------');
415 fmla_info := p_fmla_info(p_fmla_lookups(fid));
416 hr_utility.trace('Eff Start : ' ||
417 to_char(fmla_info.effective_start_date, 'DD-MON-YYYY'));
418 hr_utility.trace('Eff End : ' ||
419 to_char(fmla_info.effective_end_date, 'DD-MON-YYYY'));
420 hr_utility.trace('Fmla Name : ' || fmla_info.formula_name);
421 hr_utility.trace('Package : ' || fmla_info.package_name);
422 hr_utility.trace('First FDIU : ' || fmla_info.first_fdiu);
423 hr_utility.trace('FDIU Count : ' || fmla_info.fdiu_count);
424 hr_utility.trace('Ctx count : ' || fmla_info.context_count);
425 hr_utility.trace('In count : ' || fmla_info.input_count);
426 hr_utility.trace('Out count : ' || fmla_info.output_count);
427
428 -- Output information about the fdiu rows.
429 first := fmla_info.first_fdiu;
430 last := first + fmla_info.fdiu_count - 1;
431
432 hr_utility.trace('');
433 hr_utility.trace('FDIU ROWS');
434 hr_utility.trace('[FDIU]Item Name V[POS] I[POS] ' ||
435 'Dtype U CSum1 CSum2 ContextId');
436 hr_utility.trace('------------------------- ---------- ---------- ' ||
437 '------ - --------- --------- ----------');
438
439 for i in first..last loop
440 fdiu_info := p_fdiu_info(i);
441
442 /* build up strings first, for clarity */
443 name := rpad(fdiu_info.name, 25) || ' ';
444 varpos := rpad(fdiu_info.varpos, 10) || ' ';
445 indpos := rpad(fdiu_info.indpos, 10) || ' ';
446 data_type := rpad(fdiu_info.data_type, 6 ) || ' ';
447 usage := rpad(fdiu_info.usage, 1 ) || ' ';
448 context_sum1 := lpad(fdiu_info.context_sum1, 9 ) || ' ';
449 context_sum2 := lpad(fdiu_info.context_sum2, 9 ) || ' ';
450 context_id := lpad(fdiu_info.context_id, 10);
451
452 hr_utility.trace(name || varpos || indpos || data_type || usage ||
453 class || context_sum1 || context_sum2 ||
454 context_id);
455
456 end loop;
457
458 end if;
459 end fmla_cache_debug;
460
461 /*
462 * Debug procedure for db item cache.
463 */
464 procedure dbi_cache_debug
465 (
466 p_ctx_info in dbi_cache_t,
467 p_dbi_info in dbi_cache_t,
468 p_hash_info in dbi_hash_t
469 ) is
470 l_index varchar2(20);
471 item_name varchar2(240);
472 context_level1 varchar2(30);
473 context_level2 varchar2(30);
474 value varchar2(255);
475 indicator number;
476 first_entry varchar2(80);
477 chain_count varchar2(80);
478 i binary_integer;
479
480 begin
481 -- Check the debug flag settting.
482 if(ff_utils.g_debug_level is null or ff_utils.g_debug_level = 0) then
483 return;
484 end if;
485
486 if(bitand(ff_utils.g_debug_level, ff_exec.DBI_CACHE_DBG) <> 0) then
487 -- Debug level set correctly, output debug information for
488 -- database item cache.
489 hr_utility.trace('');
490 hr_utility.trace('[DBI]Indx DbItem/Context Name Ctx Level1 Ctx Level2' ||
491 ' Value');
492 hr_utility.trace('--------- ------------------- ----------- ----------- ' ||
493 '-----------------------------');
494
495 /*
496 * Information about the contexts.
497 */
498 i := p_ctx_info.first;
499
500 while(i is not null) loop
501
502 value := '<NULL>';
503 if p_ctx_info(i).data_type = C_DATE then
504 if p_ctx_info(i).dvalue is not null then
505 value := fnd_date.date_to_canonical( p_ctx_info(i).dvalue );
506 end if;
507 elsif p_ctx_info(i).data_type = C_NUMBER then
508 if p_ctx_info(i).nvalue is not null then
509 value := replace(to_char(p_ctx_info(i).nvalue), g_decpoint, '.');
510 end if;
511 else
512 if p_ctx_info(i).tvalue is not null then
513 value := p_ctx_info(i).tvalue;
514 end if;
515 end if;
516
517 -- Set up variables first, for clarity.
518 l_index := lpad(i, 9) || ' ';
519 item_name := rpad(p_ctx_info(i).item_name, 20) || ' ';
520 context_level1 := lpad(p_ctx_info(i).context_level1, 11) || ' ';
521 context_level2 := lpad(p_ctx_info(i).context_level2, 11) || ' ';
522
523 -- Now output the string.
524 hr_utility.trace(l_index || item_name || context_level1 || context_level2 ||
525 value);
526
527 i := p_ctx_info.next(i);
528
529 end loop;
530
531 /*
532 * Information about the database items.
533 */
534 i := p_dbi_info.first;
535
536 while(i is not null) loop
537
538 value := null;
539 if p_dbi_info(i).indicator = FF_NOT_NULL then
540 if p_dbi_info(i).data_type = C_DATE then
541 value := fnd_date.date_to_canonical( p_dbi_info(i).dvalue );
542 elsif p_dbi_info(i).data_type = C_NUMBER then
543 value := replace(to_char(p_dbi_info(i).nvalue), g_decpoint, '.');
544 else
545 value := p_dbi_info(i).tvalue;
546 end if;
547 end if;
548 value := nvl(value, '<NULL>');
549 value := value || ' ';
550
551 -- Set up variables first, for clarity.
552 l_index := lpad(i, 9) || ' ';
553 item_name := rpad(p_dbi_info(i).item_name, 20) || ' ';
554 context_level1 := lpad(p_dbi_info(i).context_level1, 11) || ' ';
555 context_level2 := lpad(p_dbi_info(i).context_level2, 11) || ' ';
556 indicator := p_dbi_info(i).indicator;
557
558 -- Now output the string.
559 hr_utility.trace(l_index || item_name || context_level1 || context_level2 ||
560 value || indicator);
561
562 i := p_dbi_info.next(i);
563
564 end loop;
565
566 /*
567 * Information about db item hash table.
568 */
569
570 hr_utility.trace('[HSH]Indx First Count');
571 hr_utility.trace('--------- --------- ---------');
572
573 i := p_hash_info.first;
574
575 while(i is not null) loop
576
577 -- Set up variables first, for clarity.
578 l_index := lpad(i, 9) || ' ';
579 first_entry := lpad(p_hash_info(i).first_entry, 9) || ' ';
580 chain_count := lpad(p_hash_info(i).chain_count, 9);
581
582 -- Now output the string.
583 hr_utility.trace(l_index || first_entry || chain_count);
584
585 i := p_hash_info.next(i);
586
587 end loop;
588
589 end if;
590
591 end dbi_cache_debug;
592
593 /*
594 * Output some info about the invalidation of database
595 * items in the cache.
596 */
597 procedure dbi_invalid_debug
598 (
599 p_dbi_info in dbi_cache_r,
600 p_context_sum1 in binary_integer,
601 p_context_sum2 in binary_integer
602 ) is
603 item_name varchar2(240);
604 context_level1 varchar2(30);
605 context_sum1 varchar2(30);
606 context_level2 varchar2(30);
607 context_sum2 varchar2(30);
608 value varchar2(255);
609 begin
610 -- Check the debug flag settting.
611 if(ff_utils.g_debug_level is null or ff_utils.g_debug_level = 0) then
612 return;
613 end if;
614
615 if(bitand(ff_utils.g_debug_level, ff_exec.DBI_CACHE_DBG) <> 0) then
616
617 item_name := rpad(p_dbi_info.item_name, 20) || ' ';
618 context_level1 := lpad(p_dbi_info.context_level1,10) || ' ';
619 context_sum1 := lpad(p_context_sum1, 10) || ' ';
620 context_level2 := lpad(p_dbi_info.context_level2,10) || ' ';
621 context_sum2 := lpad(p_context_sum2, 10) || ' ';
622
623
624 value := null;
625 if p_dbi_info.indicator = FF_NOT_NULL then
626 if p_dbi_info.data_type = C_DATE then
627 value := fnd_date.date_to_canonical( p_dbi_info.dvalue );
628 elsif p_dbi_info.data_type = C_NUMBER then
629 value := replace(to_char(p_dbi_info.nvalue), g_decpoint, '.');
630 else
631 value := p_dbi_info.tvalue;
632 end if;
633 end if;
634 value := nvl(value, '<NULL>');
635
636 hr_utility.trace('INVAL: ' || item_name || context_level1 ||
637 context_level2 || context_sum1 || context_sum2 ||
638 value);
639
640 end if;
641
642 end dbi_invalid_debug;
643
644 /*
645 * Log information about a changed context.
646 */
647 procedure ctx_change_debug
648 (
649 p_item_name in varchar2,
650 p_context_level1 in binary_integer,
651 p_context_level2 in binary_integer,
652 p_old_value in varchar2,
653 p_new_value in varchar2
654 ) is
655 item_name varchar2(240);
656 context_level1 varchar2(30);
657 context_level2 varchar2(30);
658 old_value varchar2(255);
659 new_value varchar2(255);
660 begin
661 -- Check the debug flag settting.
662 if(ff_utils.g_debug_level is null or ff_utils.g_debug_level = 0) then
663 return;
664 end if;
665
666 if(bitand(ff_utils.g_debug_level, ff_exec.DBI_CACHE_DBG) <> 0) then
667
668 item_name := rpad(p_item_name, 20) || ' ';
669 context_level1 := lpad(p_context_level1, 10) || ' ';
670 context_level2 := lpad(p_context_level2, 10) || ' ';
671 old_value := nvl(p_old_value, '<NULL>') || ' ';
672 new_value := nvl(p_new_value, '<NULL>');
673
674 hr_utility.trace('CTXCH: ' || item_name || context_level1 ||
675 context_level2 || old_value || new_value);
676 end if;
677
678 end ctx_change_debug;
679
680 /*
681 * Input and Output table information.
682 */
683 procedure io_table_debug
684 (
685 p_inputs in ff_exec.inputs_t,
686 p_outputs in ff_exec.outputs_t,
687 p_type in varchar2
688 ) is
689 l_index varchar2(20);
690 name varchar2(240);
691 data_type varchar2(20);
692 class varchar2(20);
693 value varchar2(255);
694 i binary_integer;
695
696 begin
697 -- Check the debug flag settting.
698 if(ff_utils.g_debug_level is null or ff_utils.g_debug_level = 0) then
699 return;
700 end if;
701
702 if(bitand(ff_utils.g_debug_level, ff_exec.IO_TABLE_DBG) <> 0) then
703 -- Debug level set correctly, output debug information for
704 -- input table information.
705
706 if(p_type = 'INPUT') then
707
708 /*
709 * Inputs table information.
710 */
711
712 hr_utility.trace('');
713 hr_utility.trace('[IT]Index Input/Context Name ' ||
714 'Dtype Class Value');
715 hr_utility.trace('--------- ------------------------------ ' ||
716 '------- ------- -----------------------');
717
718 i := p_inputs.first;
719
720 while(i is not null) loop
721
722 -- Set up variables first, for clarity.
723 l_index := lpad(i, 9) || ' ';
724 name := rpad(p_inputs(i).name, 30) || ' ';
725 data_type := rpad(p_inputs(i).datatype, 7) || ' ';
726 class := rpad(p_inputs(i).class, 7) || ' ';
727 value := nvl(p_inputs(i).value, '<NULL>');
728
729 -- Now output the string.
730 hr_utility.trace(l_index || name || data_type || class || value);
731
732 i := p_inputs.next(i);
733
734 end loop;
735
736 elsif(p_type = 'OUTPUT') then
737
738 /*
739 * Outputs table information.
740 */
741
742 hr_utility.trace('');
743 hr_utility.trace('[OT]Index Input/Context Name ' ||
744 'Dtype Value');
745 hr_utility.trace('--------- ------------------------------ ' ||
746 '------- -------------------------------');
747
748 i := p_outputs.first;
749
750 while(i is not null) loop
751
752 -- Set up variables first, for clarity.
753 l_index := lpad(i, 9) || ' ';
754 name := rpad(p_outputs(i).name, 30) || ' ';
755 data_type := rpad(p_outputs(i).datatype, 7) || ' ';
756 value := nvl(p_outputs(i).value, '<NULL>');
757
758 -- Now output the string.
759 hr_utility.trace(l_index || name || data_type || value);
760
761 i := p_outputs.next(i);
762
763 end loop;
764
765 end if;
766
767 end if;
768
769 end io_table_debug;
770
771 ------------------------------- find_free_chunk -------------------------------
772 /*
773 NAME
774 find_free_chunk
775 DESCRIPTION
776 Finds a free chunk to reuse and updates the free chunk list
777 accordingly.
778 */
779 procedure find_free_chunk
780 (p_chunk_size in number
781 ,p_free_chunks in out nocopy free_chunk_t
782 ,p_start out nocopy number
783 ) is
784 l_first_free binary_integer;
785 l_candidate binary_integer := null;
786 i binary_integer;
787 begin
788
789 --
790 -- Dump out the free chunk list.
791 --
792 if(bitand(ff_utils.g_debug_level, ff_exec.FF_CACHE_DBG) <> 0) then
793 hr_utility.trace('<- Free Chunk List ->');
794 i := p_free_chunks.first;
795 loop
796 exit when not p_free_chunks.exists(i);
797
798 hr_utility.trace('(' || i || ',' || p_free_chunks(i) || ')');
799
800 i := p_free_chunks.next(i);
801 end loop;
802 end if;
803
804 p_start := null;
805
806 if p_chunk_size = 0 then
807 return;
808 end if;
809
810 l_first_free := p_free_chunks.first;
811 loop
812 exit when not p_free_chunks.exists(l_first_free);
813
814 --
815 -- Got a suitable candidate free chunk. It should be
816 -- as small as possible.
817 --
818 if p_free_chunks(l_first_free) >= p_chunk_size then
819 if l_candidate is null or
820 p_free_chunks(l_first_free) < p_free_chunks(l_candidate) then
821 l_candidate := l_first_free;
822 end if;
823 end if;
824
825 l_first_free := p_free_chunks.next(l_first_free);
826 end loop;
827
828 --
829 -- Got a candidate.
830 --
831 if l_candidate is not null then
832
833 --
834 -- Adjust chunk if space is left. Take space from the end of the
835 -- chunk to avoid having to delete the record.
836 --
837 if p_free_chunks(l_candidate) > p_chunk_size then
838 p_free_chunks(l_candidate) :=
839 p_free_chunks(l_candidate) - p_chunk_size;
840
841 p_start := l_candidate + p_free_chunks(l_candidate);
842 --
843 -- The chunk is exactly p_chunk_size in length. Delete the
844 -- record.
845 --
846 else
847 p_start := l_candidate;
848 p_free_chunks.delete(l_candidate);
849 end if;
850
851 if(bitand(ff_utils.g_debug_level, ff_exec.FF_CACHE_DBG) <> 0) then
852 hr_utility.trace('Reuse chunk:'||l_candidate||','||p_chunk_size);
853 end if;
854
855 end if;
856 end find_free_chunk;
857
858 ------------------------------ add_to_free_list ------------------------------
859 /*
860 NAME
861 add_to_free_list
862 DESCRIPTION
863 Puts a range of rows onto the free list.
864 */
865 procedure add_to_free_list
866 (p_first_chunk in binary_integer
867 ,p_chunk_count in binary_integer
868 ,p_free_chunks in out nocopy free_chunk_t
869 ) is
870 l_first_chunk binary_integer;
871 l_assertion boolean;
872 l_next binary_integer;
873 --
874 procedure chunk_merge
875 (p_free_chunks in out nocopy free_chunk_t
876 ,p_merge_index in binary_integer
877 ,p_count1 in binary_integer
878 ,p_count2 in binary_integer
879 ,p_delete_index in binary_integer
880 ) is
881 begin
882 p_free_chunks(p_merge_index) := p_count1 + p_count2;
883
884 if p_delete_index is not null then
885 p_free_chunks.delete(p_delete_index);
886 end if;
887 end chunk_merge;
888 --
889 begin
890 if p_chunk_count = 0 then
891 return;
892 end if;
893
894 l_first_chunk := p_free_chunks.first;
895 loop
896 exit when not p_free_chunks.exists(l_first_chunk);
897
898 --
899 -- Look for overlap errors.
900 --
901 l_assertion :=
902 (p_first_chunk + p_chunk_count - 1 < l_first_chunk) or
903 (l_first_chunk + p_free_chunks(l_first_chunk) - 1 < p_first_chunk);
904
905 if not l_assertion then
906 if(bitand(ff_utils.g_debug_level, ff_exec.FF_CACHE_DBG) <> 0) then
907 hr_utility.trace
908 ('AddToFreeList assert failed:'||p_first_chunk||','||
909 to_char(p_chunk_count-1)|| ' overlaps :'||l_first_chunk||','||
910 to_char(p_free_chunks(l_first_chunk)-1));
911 end if;
912 end if;
913
914 ff_utils.assert
915 (p_expression => l_assertion
916 ,p_location => 'add_to_free_list:1'
917 );
918
919 --
920 -- Merge at the end of an existing chunk.
921 --
922 if p_first_chunk =
923 l_first_chunk + p_free_chunks(l_first_chunk) then
924
925 chunk_merge
926 (p_free_chunks => p_free_chunks
927 ,p_merge_index => l_first_chunk
928 ,p_count1 => p_free_chunks(l_first_chunk)
929 ,p_count2 => p_chunk_count
930 ,p_delete_index => null
931 );
932
933 --
934 -- Merged at low end, now see if it is possible to merge with
935 -- the next record to keep the list as short as possible.
936 --
937 l_next := p_free_chunks.next(l_first_chunk);
938 if p_free_chunks.exists(l_next) then
939 if p_free_chunks(l_first_chunk) + l_first_chunk = l_next then
940
941 chunk_merge
942 (p_free_chunks => p_free_chunks
943 ,p_merge_index => l_first_chunk
944 ,p_count1 => p_free_chunks(l_first_chunk)
945 ,p_count2 => p_free_chunks(l_next)
946 ,p_delete_index => l_next
947 );
948
949 end if;
950 end if;
951
952 return;
953 end if;
954
955 --
956 -- Merge at the start of an existing chunk.
957 --
958 if p_first_chunk + p_chunk_count = l_first_chunk then
959 chunk_merge
960 (p_free_chunks => p_free_chunks
961 ,p_merge_index => p_first_chunk
962 ,p_count1 => p_free_chunks(l_first_chunk)
963 ,p_count2 => p_chunk_count
964 ,p_delete_index => l_first_chunk
965 );
966 return;
967 end if;
968
969 l_first_chunk := p_free_chunks.next(l_first_chunk);
970 end loop;
971
972 --
973 -- No merge possible so create a new record.
974 --
975 p_free_chunks(p_first_chunk) := p_chunk_count;
976 end add_to_free_list;
977
978 ---------------------------- find_dbi_cache_entry -----------------------------
979 /*
980 NAME
981 find_dbi_cache_entry
982 DESCRIPTION
983 Finds the real index entry in database item cache.
984 NOTES
985 Passed the hashed context_id and returns the appropriate index
986 value for the database item we are looking for, else null.
987 */
988
989 function find_dbi_cache_entry
990 (
991 p_context_id in binary_integer,
992 p_item_name in varchar2
993 ) return binary_integer is
994 l_start binary_integer;
995 l_end binary_integer;
996 l_index binary_integer;
997 begin
998
999 ff_utils.entry('find_dbi_cache_entry');
1000
1001 if(not g_hash_info.exists(p_context_id)) then
1002 -- No entry at all for database item.
1003 ff_utils.exit('find_dbi_cache_entry');
1004 return(null);
1005 end if;
1006
1007 -- We know there is an entry, need to find out which one.
1008 l_start := g_hash_info(p_context_id).first_entry;
1009 l_end := l_start + g_hash_info(p_context_id).chain_count - 1;
1010
1011 -- Now search for the appropriate entry.
1012 for l_count in l_start..l_end loop
1013 if(g_dbi_info(l_count).item_name = p_item_name) then
1014 l_index := l_count;
1015 exit;
1016 end if;
1017 end loop;
1018
1019 ff_utils.exit('find_dbi_cache_entry');
1020
1021 return(l_index);
1022
1023 end find_dbi_cache_entry;
1024
1025 ------------------------------- read_dbi_cache --------------------------------
1026 /*
1027 NAME
1028 read_dbi_cache
1029 DESCRIPTION
1030 Reads value from database item cache.
1031 NOTES
1032 Returns value from database item cache, based on the hashed
1033 context_id and the name.
1034 */
1035
1036 procedure read_dbi_cache
1037 (
1038 p_context_id in binary_integer,
1039 p_item_name in varchar2
1040 ,p_data_type in varchar2
1041 ,p_dvalue out nocopy date
1042 ,p_nvalue out nocopy number
1043 ,p_tvalue out nocopy varchar2
1044 ,p_indicator out nocopy binary_integer
1045 ) is
1046 l_index binary_integer;
1047 begin
1048
1049 if g_debug then
1050 ff_utils.entry('read_dbi_cache');
1051 end if;
1052
1053 l_index := find_dbi_cache_entry(p_context_id, p_item_name);
1054
1055 -- Entry should exist when reading from the cache.
1056 ff_utils.assert((l_index is not null), 'read_dbi_cache:1');
1057
1058 if g_debug then
1059 ff_utils.exit('read_dbi_cache');
1060 end if;
1061
1062 -- Simply return the value from cache.
1063 if g_dbi_info(l_index).indicator = FF_NOT_NULL then
1064 if p_data_type = C_DATE then
1065 p_dvalue := g_dbi_info(l_index).dvalue;
1066 elsif p_data_type = C_NUMBER then
1067 p_nvalue := g_dbi_info(l_index).nvalue;
1068 else
1069 p_tvalue := g_dbi_info(l_index).tvalue;
1070 end if;
1071 else
1072 p_nvalue := NULL;
1073 p_dvalue := NULL;
1074 p_tvalue := NULL;
1075 end if;
1076
1077 p_indicator := g_dbi_info(l_index).indicator;
1078
1079 end read_dbi_cache;
1080
1081 ------------------------------- write_dbi_cache -------------------------------
1082 /*
1083 NAME
1084 write_dbi_cache
1085 DESCRIPTION
1086 Writes a value to db item cache.
1087 NOTES
1088 If the entry already exists, the current value is overwritten
1089 otherwise a new entry is created. The chaining from clashing
1090 hash values is dealt with.
1091
1092 Note that we default the context level to null, because
1093 we only need to pass this when the entry is first created.
1094
1095 The default is not to write to an existing entry.
1096 */
1097
1098 procedure write_dbi_cache
1099 (
1100 p_context_id in binary_integer,
1101 p_item_name in varchar2,
1102 p_data_type in varchar2,
1103 p_dvalue in date,
1104 p_nvalue in number,
1105 p_tvalue in varchar2,
1106 p_context_level1 in binary_integer default null,
1107 p_context_level2 in binary_integer default null,
1108 p_force_write in boolean default true
1109 ,p_indicator in binary_integer default FF_NULL
1110 ) is
1111 l_index binary_integer;
1112 begin
1113
1114 if g_debug then
1115 ff_utils.entry('write_dbi_cache');
1116 end if;
1117
1118 -- Look for an existing entry in the dbi cache.
1119 l_index := find_dbi_cache_entry(p_context_id, p_item_name);
1120
1121 if(l_index is not null) then
1122
1123 ff_utils.assert
1124 (p_expression => p_data_type = g_dbi_info(l_index).data_type
1125 ,p_location => 'write_dbi_cache:0'
1126 );
1127
1128 -- An entry exists, but only write if told to.
1129 if(p_force_write) then
1130 if p_indicator <> FF_NOT_NULL then
1131 if g_dbi_info(l_index).data_type = C_DATE then
1132 g_dbi_info(l_index).dvalue := NULL;
1133 elsif g_dbi_info(l_index).data_type = C_NUMBER then
1134 g_dbi_info(l_index).nvalue := NULL;
1135 else
1136 g_dbi_info(l_index).tvalue := NULL;
1137 end if;
1138 else
1139 if g_dbi_info(l_index).data_type = C_DATE then
1140 g_dbi_info(l_index).dvalue := p_dvalue;
1141 elsif g_dbi_info(l_index).data_type = C_NUMBER then
1142 g_dbi_info(l_index).nvalue := p_nvalue;
1143 else
1144 g_dbi_info(l_index).tvalue := p_tvalue;
1145 end if;
1146 end if;
1147
1148 g_dbi_info(l_index).indicator := p_indicator;
1149 end if;
1150 else
1151 /*
1152 * No entry exists, so create new one. Note that there
1153 * are two conditions that could cause this:
1154 * a) There is no hash table entry at all, in which
1155 * case both hash and dbi cache entries need to be
1156 * created.
1157 * b) There is a hash table entry, but no dbi cache
1158 * entry, in which case just the dbi cache entry
1159 * is needed.
1160 */
1161 if(not g_hash_info.exists(p_context_id)) then
1162 -- Create new hash entry.
1163 g_hash_info(p_context_id).first_entry := g_next_dbi_index;
1164 g_hash_info(p_context_id).chain_count := 1;
1165 l_index := g_next_dbi_index;
1166
1167 -- Point to next possible entry point.
1168 g_next_dbi_index := g_next_dbi_index + DBI_CACHE_INCR;
1169 else
1170 -- There is a hash index, but no entry in the cache
1171 -- itself.
1172 l_index := g_hash_info(p_context_id).first_entry +
1173 g_hash_info(p_context_id).chain_count;
1174
1175 -- Now have another entry on the chain.
1176 g_hash_info(p_context_id).chain_count :=
1177 g_hash_info(p_context_id).chain_count + 1;
1178
1179 end if;
1180
1181 -- For new create, the context level should be not null.
1182 ff_utils.assert((p_context_level1 is not null), 'write_dbi_cache:1');
1183 ff_utils.assert((p_context_level2 is not null), 'write_dbi_cache:2');
1184
1185 -- Now create the first dbi cache entry.
1186 g_dbi_info(l_index).item_name := p_item_name;
1187 g_dbi_info(l_index).context_level1 := p_context_level1;
1188 g_dbi_info(l_index).context_level2 := p_context_level2;
1189 g_dbi_info(l_index).data_type := p_data_type;
1190
1191 if p_indicator <> FF_NOT_NULL then
1192 if g_dbi_info(l_index).data_type = C_DATE then
1193 g_dbi_info(l_index).dvalue := NULL;
1194 elsif g_dbi_info(l_index).data_type = C_NUMBER then
1195 g_dbi_info(l_index).nvalue := NULL;
1196 else
1197 g_dbi_info(l_index).tvalue := NULL;
1198 end if;
1199 else
1200 if g_dbi_info(l_index).data_type = C_DATE then
1201 g_dbi_info(l_index).dvalue := p_dvalue;
1202 elsif g_dbi_info(l_index).data_type = C_NUMBER then
1203 g_dbi_info(l_index).nvalue := p_nvalue;
1204 else
1205 g_dbi_info(l_index).tvalue := p_tvalue;
1206 end if;
1207 end if;
1208
1209 g_dbi_info(l_index).indicator := p_indicator;
1210 end if;
1211
1212 if g_debug then
1213 ff_utils.exit('write_dbi_cache');
1214 end if;
1215
1216 end write_dbi_cache;
1217
1218 ------------------------ get_next_context_level -------------------------------
1219 /*
1220 NAME
1221 get_next_context_level
1222 DESCRIPTION
1223 Allocates the next formula context level bit.
1224 */
1225 procedure get_next_context_level
1226 (p_context_level1 out nocopy binary_integer
1227 ,p_context_level2 out nocopy binary_integer
1228 ) is
1229 begin
1230 if g_ctx_levels1 < C_MASK_BITS then
1231 p_context_level1 := 2 ** g_ctx_levels1;
1232 p_context_level2 := 0;
1233 g_ctx_levels1 := g_ctx_levels1 + 1;
1234 elsif g_ctx_levels2 < C_MASK_BITS then
1235 p_context_level2 := 2 ** g_ctx_levels2;
1236 p_context_level1 := 0;
1237 g_ctx_levels2 := g_ctx_levels2 + 1;
1238 else
1239 hr_utility.set_message(801, 'FF_33289_CONTEXT_CACHE_FULL');
1240 hr_utility.set_message_token('1', C_MAX_CONTEXTS);
1241 hr_utility.raise_error;
1242 end if;
1243 end get_next_context_level;
1244
1245 ----------------------------- dbi2route_id ------------------------------------
1246 /*
1247 NAME
1248 dbi2route_id
1249 DESCRIPTION
1250 Fetches the route_id given a database item name.
1251 NOTES
1252 p_business_group_id and p_legislation_code must come direct from
1253 ff_formulas_f i.e. p_legislation_code must not be derived from
1254 p_business_group_id.
1255 */
1256 function dbi2route_id
1257 (p_formula_name in varchar2
1258 ,p_dbi_name in varchar2
1259 ,p_business_group_id in number
1260 ,p_legislation_code in varchar2
1261 ) return binary_integer is
1262 cursor csr_route_id
1263 (p_dbi_name in varchar2
1264 ,p_business_group_id in number
1265 ,p_legislation_code in varchar2
1266 ) is
1267 select u.route_id
1268 from ff_database_items d
1269 , ff_user_entities u
1270 where d.user_name = p_dbi_name
1271 and d.user_entity_id = u.user_entity_id
1272 and (
1273 u.legislation_code is null and u.business_group_id is null or
1274 u.legislation_code = p_legislation_code or
1275 u.business_group_id = p_business_group_id or
1276 u.legislation_code =
1277 (
1278 select b.legislation_code
1279 from per_business_groups_perf b
1280 where b.business_group_id = p_business_group_id
1281 )
1282 )
1283 ;
1284 l_route_id binary_integer;
1285 begin
1286 open csr_route_id
1287 (p_dbi_name => p_dbi_name
1288 ,p_business_group_id => p_business_group_id
1289 ,p_legislation_code => p_legislation_code
1290 );
1291 fetch csr_route_id
1292 into l_route_id
1293 ;
1294 if csr_route_id%notfound then
1295 close csr_route_id;
1296 --
1297 -- Ask user to recompile because of potential data dictionary
1298 -- problem.
1299 --
1300 hr_utility.set_message(801, 'FFXBIF71_NEED_TO_REVERIFY');
1301 hr_utility.set_message_token('1', p_formula_name);
1302 hr_utility.raise_error;
1303 end if;
1304 close csr_route_id;
1305
1306 return l_route_id;
1307 end dbi2route_id;
1308
1309 ---------------------------- get_route_info -----------------------------------
1310 /*
1311 NAME
1312 get_route_info
1313 DESCRIPTION
1314 Fetches the route context information for given a route_id.
1315 */
1316 procedure get_route_info
1317 (p_formula_name in varchar2
1318 ,p_route_id in binary_integer
1319 ,p_context_sum1 out nocopy binary_integer
1320 ,p_context_sum2 out nocopy binary_integer
1321 ) is
1322 cursor csr_route_exists(p_route_id in binary_integer) is
1323 select null
1324 from ff_routes r
1325 where r.route_id = p_route_id
1326 ;
1327 --
1328 cursor csr_route_contexts
1329 (p_route_id in number
1330 ) is
1331 select rcu.context_id
1332 from ff_route_context_usages rcu
1333 where rcu.route_id = p_route_id
1334 ;
1335
1336 l_context_ids t_binary_integer;
1337 l_sum1 binary_integer := 0;
1338 l_sum2 binary_integer := 0;
1339 l_dummy varchar2(1);
1340 begin
1341 --
1342 -- Are the context sums for p_route_id already cached ?
1343 --
1344 if not g_route_ctx_sums.exists(p_route_id) then
1345 -- Validate that the route itself exists.
1346 open csr_route_exists(p_route_id => p_route_id);
1347 fetch csr_route_exists
1348 into l_dummy;
1349 if csr_route_exists%notfound then
1350 close csr_route_exists;
1351 --
1352 -- Ask user to recompile because of potential data dictionary
1353 -- problem.
1354 --
1355 hr_utility.set_message(801, 'FFXBIF71_NEED_TO_REVERIFY');
1356 hr_utility.set_message_token('1', p_formula_name);
1357 hr_utility.raise_error;
1358 end if;
1359 close csr_route_exists;
1360
1361 open csr_route_contexts(p_route_id => p_route_id);
1362 fetch csr_route_contexts bulk collect
1363 into l_context_ids;
1364 close csr_route_contexts;
1365 for i in 1 .. l_context_ids.count loop
1366 if not g_ctx_info.exists(l_context_ids(i)) then
1367 --
1368 -- Ask user to recompile because of potential data dictionary
1369 -- problem.
1370 --
1371 hr_utility.set_message(801, 'FFXBIF71_NEED_TO_REVERIFY');
1372 hr_utility.set_message_token('1', p_formula_name);
1373 hr_utility.raise_error;
1374 end if;
1375
1376 l_sum1 := l_sum1 + g_ctx_info(l_context_ids(i)).context_level1;
1377 l_sum2 := l_sum2 + g_ctx_info(l_context_ids(i)).context_level2;
1378 end loop;
1379
1380 --
1381 -- Cache the context level sums.
1382 --
1383 g_route_ctx_sums(p_route_id).context_sum1 := l_sum1;
1384 g_route_ctx_sums(p_route_id).context_sum2 := l_sum2;
1385 end if;
1386
1387 p_context_sum1 := g_route_ctx_sums(p_route_id).context_sum1;
1388 p_context_sum2 := g_route_ctx_sums(p_route_id).context_sum2;
1389 end get_route_info;
1390
1391 ------------------------------- ff_fetch --------------------------------------
1392 /*
1393 NAME
1394 ff_fetch
1395 DESCRIPTION
1396 Fetches specified formula information.
1397 NOTES
1398 Performs the actual fetches to put load the data
1399 for a specified formula into the internal
1400 cache structures.
1401 */
1402
1403 procedure ff_fetch
1404 (
1405 p_free_slot in binary_integer,
1406 p_formula_id in binary_integer,
1407 p_effective_date in date,
1408 p_fmla_lookups in out nocopy fmla_lookup_t,
1409 p_fmla_info in out nocopy fmla_info_t,
1410 p_fdiu_info in out nocopy fdiu_info_t,
1411 p_ctx_info in out nocopy dbi_cache_t
1412 ) is
1413
1414 cursor fdiuc1 is
1415 select fdiu.item_name name,
1416 to_number(substr(fdiu.item_generated_name, 2)) varpos,
1417 decode(fdiu.indicator_var_name, NULL, INVALID_POS,
1418 to_number(substr(fdiu.indicator_var_name, 2))) indpos,
1419 decode(fdiu.data_type,
1420 'D', 'DATE',
1421 'N', 'NUMBER',
1422 'T', 'TEXT', 'XXX') data_type,
1423 fdiu.usage,
1424 decode(fdiu.usage,
1425 'U', 1,
1426 'I', 2, 'B', 2, 'O', 2,
1427 'D', 3) usageorder,
1428 0 context_sum1,
1429 0 context_sum2,
1430 fdiu.context_id,
1431 fdiu.route_id
1432 from ff_fdi_usages_f fdiu
1433 where fdiu.formula_id = p_formula_id
1434 and p_effective_date between
1435 fdiu.effective_start_date and fdiu.effective_end_date
1436 and fdiu.load_when_running = 'Y'
1437 order by 6, fdiu.item_name; -- *** IMPORTANT.
1438
1439 l_effective_start_date date;
1440 l_effective_end_date date;
1441 l_formula_name ff_formulas_f.formula_name%type;
1442 l_fdiu_entry_count ff_compiled_info_f.fdiu_entry_count%type;
1443 l_package_name varchar2(60);
1444 l_first_fdiu binary_integer;
1445 l_fdiu_row binary_integer; -- latest fdiu row.
1446 l_fdiu_count binary_integer;
1447 l_input_count binary_integer := 0; -- count inputs for formula.
1448 l_output_count binary_integer := 0; -- count outputs for formula.
1449 l_context_count binary_integer := 0; -- count contexts for formula.
1450 l_business_group_id number;
1451 l_legislation_code varchar2(30);
1452
1453 --
1454 -- Separate tables making up the in-core FDIU to allow bulk binds.
1455 --
1456 l_fdiu_name t_big_varchar2;
1457 l_fdiu_varpos t_binary_integer;
1458 l_fdiu_indpos t_binary_integer;
1459 l_fdiu_data_type t_small_varchar2;
1460 l_fdiu_usage t_small_varchar2;
1461 l_fdiu_usage_order t_small_varchar2;
1462 l_fdiu_context_sum1 t_binary_integer;
1463 l_fdiu_context_sum2 t_binary_integer;
1464 l_fdiu_context_id t_binary_integer;
1465 l_fdiu_route_id t_binary_integer;
1466
1467 --
1468 -- Local copies of the parameters which are only updated at the end
1469 -- of the procedure call to avoid exceptions.
1470 --
1471 l_fmla_info fmla_info_r;
1472 l_fdiu_info fdiu_info_t;
1473 i binary_integer;
1474 l_got_fdiu_chunks boolean := false;
1475 l_reused boolean := false;
1476 l_assertion boolean;
1477
1478 begin
1479
1480 if g_debug then
1481 ff_utils.entry('ff_fetch');
1482 end if;
1483
1484 /*
1485 * Fetch formula information.
1486 */
1487 begin
1488 select 'FFP' || fff.formula_id || '_' ||
1489 to_char(fff.effective_start_date, 'DDMMYYYY'),
1490 fff.effective_start_date,
1491 fff.effective_end_date,
1492 fff.formula_name,
1493 fff.business_group_id,
1494 fff.legislation_code,
1495 fci.fdiu_entry_count
1496 into l_package_name,
1497 l_effective_start_date,
1498 l_effective_end_date,
1499 l_formula_name,
1500 l_business_group_id,
1501 l_legislation_code,
1502 l_fdiu_entry_count
1503 from ff_formulas_f fff,
1504 ff_compiled_info_f fci
1505 where fff.formula_id = p_formula_id
1506 and p_effective_date between
1507 fff.effective_start_date and fff.effective_end_date
1508 and fci.formula_id = fff.formula_id
1509 and p_effective_date between
1510 fci.effective_start_date and fci.effective_end_date;
1511 exception
1512 --
1513 -- Handle the case where there is no compiled formula.
1514 --
1515 when no_data_found then
1516 hr_utility.set_message(801, 'FFX22J_FORMULA_NOT_FOUND');
1517 hr_utility.set_message_token('1', p_formula_id);
1518 hr_utility.raise_error;
1519 when others then
1520 raise;
1521 end;
1522
1523 /*
1524 * Load the formula cache structure.
1525 * Note that the fdiu_count and mru_entry members
1526 * are set up later in this procedure.
1527 */
1528 l_fmla_info.formula_id := p_formula_id;
1529 l_fmla_info.effective_start_date := l_effective_start_date;
1530 l_fmla_info.effective_end_date := l_effective_end_date;
1531 l_fmla_info.formula_name := l_formula_name;
1532 l_fmla_info.package_name := l_package_name;
1533
1534 open fdiuc1;
1535 fetch fdiuc1 bulk collect
1536 into l_fdiu_name,
1537 l_fdiu_varpos,
1538 l_fdiu_indpos,
1539 l_fdiu_data_type,
1540 l_fdiu_usage,
1541 l_fdiu_usage_order,
1542 l_fdiu_context_sum1,
1543 l_fdiu_context_sum2,
1544 l_fdiu_context_id,
1545 l_fdiu_route_id;
1546 close fdiuc1;
1547
1548 -- Check that number of fdiu entries matches the fdiu count
1549 ff_utils.assert((l_fdiu_entry_count = l_fdiu_name.count),
1550 'ff_fetch:1');
1551
1552 --
1553 -- See if it is possible to reuse free fdiu records.
1554 --
1555 find_free_chunk
1556 (p_chunk_size => l_fdiu_entry_count
1557 ,p_free_chunks => g_free_fdiu
1558 ,p_start => l_first_fdiu
1559 );
1560 if l_first_fdiu is null then
1561 l_first_fdiu := nvl(p_fdiu_info.last, 0) + 1;
1562
1563 if(bitand(ff_utils.g_debug_level, ff_exec.FF_CACHE_DBG) <> 0) then
1564 hr_utility.trace
1565 ('ff_fetch add to FDIU from end of list:' || l_first_fdiu || ',' ||
1566 l_fdiu_entry_count
1567 );
1568 end if;
1569
1570 --
1571 -- This is a check for free FDIU list consistency.
1572 --
1573 if g_free_fdiu.last is not null then
1574 l_assertion :=
1575 l_first_fdiu > g_free_fdiu.last + g_free_fdiu(g_free_fdiu.last) - 1;
1576
1577 if not l_assertion and
1578 (bitand(ff_utils.g_debug_level, ff_exec.FF_CACHE_DBG) <> 0) then
1579 hr_utility.trace
1580 ('ff_fetch assertion 2 failed:'||l_first_fdiu||','||
1581 to_char(g_free_fdiu.last + g_free_fdiu(g_free_fdiu.last) - 1)
1582 );
1583 end if;
1584
1585 ff_utils.assert(l_assertion, 'ff_fetch:2');
1586 end if;
1587 else
1588 l_reused := true;
1589 end if;
1590
1591 -- Init the counters as required.
1592 l_first_fdiu := nvl(l_first_fdiu, 0);
1593 l_fmla_info.first_fdiu := l_first_fdiu;
1594 l_fdiu_row := l_first_fdiu;
1595
1596 -- Fetch the rows into fdiu for formula.
1597 for i in 1 .. l_fdiu_name.count loop
1598
1599 -- Process according to usage.
1600 if(l_fdiu_usage(i) = 'U' or l_fdiu_usage(i) = 'D')
1601 then
1602 -- There MUST be a context_id for 'U' or 'D'.
1603 if(l_fdiu_context_id(i) is null) then
1604 hr_utility.set_message(801, 'FFPLX01_CONTEXT_ID_NULL');
1605 hr_utility.set_message_token('FMLA_NAME', l_formula_name);
1606 hr_utility.set_message_token('ITEM_NAME', l_fdiu_name(i));
1607 hr_utility.raise_error;
1608 end if;
1609
1610 if(l_fdiu_usage(i) = 'U') then
1611 l_context_count := l_context_count + 1; -- count contexts.
1612
1613 -- Write to context cache if no existing entry.
1614 if(not p_ctx_info.exists(l_fdiu_context_id(i))) then
1615
1616 -- Dynamically allocate the context level.
1617 get_next_context_level
1618 (p_context_level1 => l_fdiu_context_sum1(i)
1619 ,p_context_level2 => l_fdiu_context_sum2(i)
1620 );
1621
1622 p_ctx_info(l_fdiu_context_id(i)).item_name := l_fdiu_name(i);
1623 p_ctx_info(l_fdiu_context_id(i)).dvalue := NULL;
1624 p_ctx_info(l_fdiu_context_id(i)).nvalue := NULL;
1625 p_ctx_info(l_fdiu_context_id(i)).tvalue := NULL;
1626 p_ctx_info(l_fdiu_context_id(i)).context_level1 :=
1627 l_fdiu_context_sum1(i);
1628 p_ctx_info(l_fdiu_context_id(i)).context_level2 :=
1629 l_fdiu_context_sum2(i);
1630 else
1631
1632 -- Get context level from the context cache.
1633 l_fdiu_context_sum1(i) :=
1634 p_ctx_info(l_fdiu_context_id(i)).context_level1;
1635 l_fdiu_context_sum2(i) :=
1636 p_ctx_info(l_fdiu_context_id(i)).context_level2;
1637 end if;
1638 else
1639 -- Must be a database item. Write an entry to cache
1640 -- if it doesn't exist.
1641
1642 --
1643 -- First perform some route_id validation.
1644 --
1645 if l_fdiu_route_id(i) is null then
1646 l_fdiu_route_id(i) :=
1647 dbi2route_id
1648 (p_formula_name => l_formula_name
1649 ,p_dbi_name => l_fdiu_name(i)
1650 ,p_business_group_id => l_business_group_id
1651 ,p_legislation_code => l_legislation_code
1652 );
1653 end if;
1654 --
1655 get_route_info
1656 (p_formula_name => l_formula_name
1657 ,p_route_id => l_fdiu_route_id(i)
1658 ,p_context_sum1 => l_fdiu_context_sum1(i)
1659 ,p_context_sum2 => l_fdiu_context_sum2(i)
1660 );
1661 --
1662 write_dbi_cache
1663 (p_context_id => l_fdiu_context_id(i)
1664 ,p_item_name => l_fdiu_name(i)
1665 ,p_data_type => l_fdiu_data_type(i)
1666 ,p_dvalue => NULL
1667 ,p_nvalue => NULL
1668 ,p_tvalue => NULL
1669 ,p_context_level1 => l_fdiu_context_sum1(i)
1670 ,p_context_level2 => l_fdiu_context_sum2(i)
1671 ,p_force_write => FALSE
1672 ,p_indicator => FF_NULL
1673 );
1674 end if;
1675
1676 end if;
1677
1678 if(l_fdiu_usage(i) in ('I', 'B')) then
1679 l_input_count := l_input_count + 1; -- count inputs and outputs.
1680 end if;
1681
1682 if(l_fdiu_usage(i) in ('O', 'B')) then -- count outputs.
1683 l_output_count := l_output_count + 1;
1684 end if;
1685
1686 /*
1687 * Set up in core fdiu entries.
1688 * It is safe to update the global structure because it can't be used
1689 * until the formula information structures are updated.
1690 */
1691 p_fdiu_info(l_fdiu_row).name := l_fdiu_name(i);
1692 p_fdiu_info(l_fdiu_row).varpos := l_fdiu_varpos(i);
1693 p_fdiu_info(l_fdiu_row).indpos := l_fdiu_indpos(i);
1694 p_fdiu_info(l_fdiu_row).data_type := l_fdiu_data_type(i);
1695 p_fdiu_info(l_fdiu_row).usage := l_fdiu_usage(i);
1696 p_fdiu_info(l_fdiu_row).context_sum1 := l_fdiu_context_sum1(i);
1697 p_fdiu_info(l_fdiu_row).context_sum2 := l_fdiu_context_sum2(i);
1698 p_fdiu_info(l_fdiu_row).context_id := l_fdiu_context_id(i);
1699 --
1700 if not l_got_fdiu_chunks then
1701 l_got_fdiu_chunks := true;
1702 end if;
1703
1704 -- Increment the row counter.
1705 l_fdiu_row := l_fdiu_row + 1;
1706
1707 end loop;
1708
1709 -- Set up the number of rows in fdiu for this formula.
1710 l_fmla_info.fdiu_count := l_fdiu_row - l_first_fdiu;
1711
1712 -- Record the context, input and output count.
1713 l_fmla_info.context_count := l_context_count;
1714 l_fmla_info.input_count := l_input_count;
1715 l_fmla_info.output_count := l_output_count;
1716
1717 --
1718 -- Can safely update the global information now.
1719 --
1720 p_fmla_info(p_free_slot) := l_fmla_info;
1721 p_fmla_lookups(p_formula_id) := p_free_slot;
1722
1723 if g_debug then
1724 ff_utils.exit('ff_fetch');
1725 end if;
1726
1727 exception
1728 when others then
1729 if fdiuc1%isopen then
1730 close fdiuc1;
1731 end if;
1732 --
1733 -- If chunks were reused then return them to the free list.
1734 --
1735 if l_reused then
1736 if(bitand(ff_utils.g_debug_level, ff_exec.FF_CACHE_DBG) <> 0) then
1737 hr_utility.trace('ff_fetch return reused rows to free list.');
1738 end if;
1739
1740 add_to_free_list
1741 (p_first_chunk => l_fmla_info.first_fdiu
1742 ,p_chunk_count => l_fdiu_entry_count
1743 ,p_free_chunks => g_free_fdiu
1744 );
1745 --
1746 -- If the chunks weren't reused then they were allocated from
1747 -- the end of the fdiu list.
1748 --
1749 elsif l_got_fdiu_chunks then
1750 if(bitand(ff_utils.g_debug_level, ff_exec.FF_CACHE_DBG) <> 0) then
1751 hr_utility.trace('ff_fetch add new rows to free list.');
1752 end if;
1753
1754 add_to_free_list
1755 (p_first_chunk => l_fmla_info.first_fdiu
1756 ,p_chunk_count => p_fdiu_info.last - l_fmla_info.first_fdiu
1757 ,p_free_chunks => g_free_fdiu
1758 );
1759 end if;
1760 --
1761 if g_debug then
1762 ff_utils.exit('ff_fetch:2');
1763 end if;
1764 --
1765 raise;
1766 end ff_fetch;
1767
1768 -------------------------------- set_lru_slot ---------------------------------
1769 /*
1770 NAME
1771 set_lru_slot
1772 DESCRIPTION
1773 Set the LRU slot to (for deleting when the cache is full).
1774 NOTES
1775 */
1776 procedure set_lru_slot
1777 (p_fmla_lookups in fmla_lookup_t
1778 ,p_exec_info in exec_info_r
1779 ,p_mru_slot in binary_integer
1780 ,p_lru_slot in out nocopy binary_integer
1781 ) is
1782 begin
1783 --
1784 -- The cache is full - LRU slot is used to cycle through a circular
1785 -- buffer. Only change the LRU slot if it's the same as the MRU slot.
1786 --
1787 if p_fmla_lookups.count >= p_exec_info.fmla_cache_size and
1788 p_lru_slot = p_mru_slot then
1789
1790 -- Handle getting to the end of the buffer.
1791 if p_lru_slot = p_exec_info.fmla_cache_size then
1792 if(bitand(ff_utils.g_debug_level, ff_exec.MRU_DBG) <> 0) then
1793 hr_utility.trace('LRU = 1');
1794 end if;
1795
1796 p_lru_slot := 1;
1797 else
1798 if(bitand(ff_utils.g_debug_level, ff_exec.MRU_DBG) <> 0) then
1799 hr_utility.trace('LRU := LRU + 1:' || to_char(p_lru_slot + 1));
1800 end if;
1801
1802 p_lru_slot := p_lru_slot + 1;
1803 end if;
1804 end if;
1805 end set_lru_slot;
1806 ---------------------------- load_formula -------------------------------------
1807 /*
1808 NAME
1809 load_formula
1810 DESCRIPTION
1811 Loads information for specific formula into formula cache.
1812 NOTES
1813 Formula information is loaded as appropriate into the
1814 various cache structures.
1815 */
1816
1817 procedure load_formula
1818 (
1819 p_formula_id in number,
1820 p_effective_date in date,
1821 p_exec_info in out nocopy exec_info_r,
1822 p_fmla_lookups in out nocopy fmla_lookup_t,
1823 p_fmla_info in out nocopy fmla_info_t,
1824 p_lru_slot in out nocopy binary_integer,
1825 p_fdiu_info in out nocopy fdiu_info_t,
1826 p_ctx_info in out nocopy dbi_cache_t
1827 ) is
1828 -- Local variable defintions.
1829 l_cache_slot binary_integer;
1830 l_need_to_fetch boolean;
1831
1832 /*
1833 * Local procedure to zap cache rows
1834 * for a specified formula.
1835 */
1836 procedure zap_fcr (p_free_slot in binary_integer,
1837 p_fmla_lookups in out nocopy fmla_lookup_t,
1838 p_fmla_info in out nocopy fmla_info_t,
1839 p_fdiu_info in out nocopy fdiu_info_t) is
1840 begin
1841
1842 if g_debug then
1843 ff_utils.entry('zap_fcr');
1844 end if;
1845
1846 ff_utils.assert(p_fmla_info.exists(p_free_slot), 'zap_fcr:1');
1847
1848 --
1849 -- Check that this slot has not been zapped previously.
1850 --
1851 if p_fmla_info(p_free_slot).formula_id is null then
1852 return;
1853 end if;
1854
1855 --
1856 -- Make sure that the reference to this slot is removed.
1857 --
1858 p_fmla_lookups(p_fmla_info(p_free_slot).formula_id) := null;
1859
1860 --
1861 -- Mark the FDIU rows as free for reuse.
1862 --
1863 if(p_fmla_info(p_free_slot).fdiu_count > 0) then
1864 add_to_free_list
1865 (p_first_chunk => p_fmla_info(p_free_slot).first_fdiu
1866 ,p_chunk_count => p_fmla_info(p_free_slot).fdiu_count
1867 ,p_free_chunks => g_free_fdiu
1868 );
1869 end if;
1870
1871 --
1872 -- Make sure that this slot cannot be used.
1873 --
1874 p_fmla_info(p_free_slot).formula_id := null;
1875 p_fmla_info(p_free_slot).fdiu_count := null;
1876 p_fmla_info(p_free_slot).first_fdiu := null;
1877
1878 if g_debug then
1879 ff_utils.exit('zap_fcr');
1880 end if;
1881
1882 end zap_fcr;
1883
1884 begin
1885
1886 if g_debug then
1887 ff_utils.entry('load_formula');
1888 end if;
1889
1890 /*
1891 * Load formula information into internal structures.
1892 */
1893 l_need_to_fetch := true;
1894
1895 --
1896 -- Check for an entry for the formula in the cache and validate
1897 -- the date range.
1898 --
1899 if p_fmla_lookups.exists(p_formula_id) and
1900 p_fmla_lookups(p_formula_id) is not null then
1901 l_cache_slot := p_fmla_lookups(p_formula_id);
1902 if p_effective_date < p_fmla_info(l_cache_slot).effective_start_date or
1903 p_effective_date > p_fmla_info(l_cache_slot).effective_end_date
1904 then
1905 -- Zap rows from cache for this formula.
1906 zap_fcr(l_cache_slot, p_fmla_lookups, p_fmla_info, p_fdiu_info);
1907 else
1908 -- The dates match so there is no need to fetch.
1909 l_need_to_fetch := false;
1910 end if;
1911 --
1912 -- Handle the case where the formula is not in the cache, but the cache is
1913 -- full.
1914 --
1915 elsif p_fmla_lookups.count >= p_exec_info.fmla_cache_size then
1916 --
1917 -- Get the formula_id from the lru slot.
1918 --
1919 zap_fcr(p_lru_slot, p_fmla_lookups, p_fmla_info, p_fdiu_info);
1920 l_cache_slot := p_lru_slot;
1921 --
1922 -- Empty slots are available, so put onto the end of the cache list.
1923 --
1924 else
1925 l_cache_slot := p_fmla_info.count + 1;
1926 p_fmla_info.extend(1);
1927 end if;
1928
1929 --
1930 -- Fetch formula details.
1931 --
1932 if (l_need_to_fetch) then
1933 ff_fetch (l_cache_slot, p_formula_id, p_effective_date, p_fmla_lookups,
1934 p_fmla_info, p_fdiu_info, p_ctx_info);
1935 end if;
1936
1937 -- Debugging output.
1938 if g_debug then
1939 fmla_cache_debug(p_formula_id, p_fmla_lookups, p_fmla_info, p_fdiu_info);
1940 end if;
1941
1942 -- Set up the global environment with current formula details.
1943 p_exec_info.formula_id := p_formula_id;
1944 p_exec_info.cache_slot := l_cache_slot;
1945 p_exec_info.effective_date := p_effective_date;
1946
1947 -- Indicate to outside world how many contexts, inputs and
1948 -- outputs the formula is expecting.
1949 ff_exec.context_count := p_fmla_info(l_cache_slot).context_count;
1950 ff_exec.input_count := p_fmla_info(l_cache_slot).input_count;
1951 ff_exec.output_count := p_fmla_info(l_cache_slot).output_count;
1952
1953 -- Reset the LRU slot.
1954 set_lru_slot(p_fmla_lookups, p_exec_info, l_cache_slot, p_lru_slot);
1955
1956 if g_debug then
1957 ff_utils.exit('load_formula');
1958 end if;
1959
1960 end load_formula;
1961
1962 ----------------------------- invalidate_db_items -----------------------------
1963 /*
1964 NAME
1965 invalidate_db_items
1966 DESCRIPTION
1967 Invalidate db items if necessary, following context value change.
1968 NOTES
1969 Skulls through datbase item cache list, invalidating (writing null to)
1970 the item if necessary.
1971 */
1972
1973 procedure invalidate_db_items
1974 (
1975 p_context_sum1 in binary_integer,
1976 p_context_sum2 in binary_integer
1977 ) is
1978 l_index binary_integer;
1979 l_path binary_integer;
1980 begin
1981 if g_debug then
1982 ff_utils.entry('invalidate_db_items');
1983 end if;
1984
1985 if p_context_sum1 <> 0 and p_context_sum2 = 0 then
1986 l_path := 1;
1987 elsif p_context_sum1 = 0 and p_context_sum2 <> 0 then
1988 l_path := 2;
1989 elsif p_context_sum1 <> 0 and p_context_sum2 <> 0 then
1990 l_path := 3;
1991 else
1992 --
1993 -- The bit masks are both 0 so no need to do anything.
1994 --
1995 return;
1996 end if;
1997
1998 if l_path = 1 then
1999 l_index := g_dbi_info.first;
2000
2001 while(l_index is not null) loop
2002
2003 if(bitand(p_context_sum1, g_dbi_info(l_index).context_level1) <> 0)
2004 then
2005 if g_debug then
2006 dbi_invalid_debug
2007 (g_dbi_info(l_index)
2008 ,p_context_sum1
2009 ,p_context_sum2
2010 );
2011 end if;
2012 g_dbi_info(l_index).indicator := FF_NULL;
2013 g_dbi_info(l_index).dvalue := NULL;
2014 g_dbi_info(l_index).nvalue := NULL;
2015 g_dbi_info(l_index).tvalue := NULL;
2016 end if;
2017
2018 l_index := g_dbi_info.next(l_index);
2019 end loop;
2020 elsif l_path = 2 then
2021
2022 l_index := g_dbi_info.first;
2023
2024 while(l_index is not null) loop
2025
2026 if(bitand(p_context_sum2, g_dbi_info(l_index).context_level2) <> 0)
2027 then
2028 if g_debug then
2029 dbi_invalid_debug
2030 (g_dbi_info(l_index)
2031 ,p_context_sum1
2032 ,p_context_sum2
2033 );
2034 end if;
2035 g_dbi_info(l_index).indicator := FF_NULL;
2036 g_dbi_info(l_index).dvalue := NULL;
2037 g_dbi_info(l_index).nvalue := NULL;
2038 g_dbi_info(l_index).tvalue := NULL;
2039 end if;
2040
2041 l_index := g_dbi_info.next(l_index);
2042 end loop;
2043 else
2044 l_index := g_dbi_info.first;
2045
2046 while(l_index is not null) loop
2047
2048 if(bitand(p_context_sum1, g_dbi_info(l_index).context_level1) <> 0 or
2049 bitand(p_context_sum2, g_dbi_info(l_index).context_level2) <> 0)
2050 then
2051 if g_debug then
2052 dbi_invalid_debug
2053 (g_dbi_info(l_index)
2054 ,p_context_sum1
2055 ,p_context_sum2
2056 );
2057 end if;
2058 g_dbi_info(l_index).indicator := FF_NULL;
2059 g_dbi_info(l_index).dvalue := NULL;
2060 g_dbi_info(l_index).nvalue := NULL;
2061 g_dbi_info(l_index).tvalue := NULL;
2062 end if;
2063
2064 l_index := g_dbi_info.next(l_index);
2065 end loop;
2066 end if;
2067
2068 if g_debug then
2069 ff_utils.exit('invalidate_db_items');
2070 end if;
2071
2072 end invalidate_db_items;
2073
2074 ------------------------------ bind_variables ---------------------------------
2075 /*
2076 NAME
2077 bind_variables
2078 DESCRIPTION
2079 Deals with binding the anonymous block PLSQL variables.
2080 NOTES
2081 Called from the run_formula procedure.
2082 */
2083
2084 procedure bind_variables
2085 (
2086 p_cache_slot in binary_integer,
2087 p_inputs in ff_exec.inputs_t,
2088 p_outputs in ff_exec.outputs_t,
2089 p_fmla_info in fmla_info_t,
2090 p_fdiu_info in fdiu_info_t,
2091 p_ctx_info in out nocopy dbi_cache_t,
2092 p_d in out nocopy ff_wrapper_pkg.t_date,
2093 p_n in out nocopy ff_wrapper_pkg.t_number,
2094 p_t in out nocopy ff_wrapper_pkg.t_text,
2095 p_i in out nocopy ff_wrapper_pkg.t_number,
2096 p_use_dbi_cache in boolean
2097 ) is
2098
2099 l_context_total1 binary_integer;
2100 l_context_total2 binary_integer;
2101 l_first_fdiu binary_integer;
2102 l_last_fdiu binary_integer;
2103 l_count binary_integer;
2104 l_item_name varchar2(240);
2105 l_varpos binary_integer;
2106 l_indpos binary_integer;
2107 l_indic_value binary_integer;
2108 l_dvalue date;
2109 l_nvalue number;
2110 l_tvalue varchar2(255); -- matches ff_exec.FF_BIND_LEN
2111 l_data_type varchar2(7);
2112 l_usage varchar2(1);
2113 l_context_id binary_integer; -- context_id.
2114 l_context_sum1 binary_integer;
2115 l_context_sum2 binary_integer;
2116 l_context_count binary_integer;
2117 l_in_index binary_integer; -- only interested in count of inputs.
2118 begin
2119
2120 if g_debug then
2121 ff_utils.entry('bind_variables');
2122 end if;
2123
2124 l_context_total1 := 0;
2125 l_context_total2 := 0;
2126 l_context_count := 0;
2127 l_in_index := 0;
2128
2129 /*
2130 * Bind variables body.
2131 */
2132 l_first_fdiu := p_fmla_info(p_cache_slot).first_fdiu;
2133 l_last_fdiu := l_first_fdiu + p_fmla_info(p_cache_slot).fdiu_count - 1;
2134
2135 for l_count in l_first_fdiu..l_last_fdiu loop
2136 /*
2137 * Get the value to bind.
2138 * Where we get this from depends on the usage.
2139 * Note how the fdiu is ordered, this is important.
2140 * Assign some values to local variables to make the
2141 * code a little easier to understand.
2142 */
2143 l_item_name := p_fdiu_info(l_count).name;
2144 l_varpos := p_fdiu_info(l_count).varpos;
2145 l_indpos := p_fdiu_info(l_count).indpos;
2146 l_indic_value := null;
2147 l_data_type := p_fdiu_info(l_count).data_type;
2148 l_usage := p_fdiu_info(l_count).usage;
2149 l_context_id := p_fdiu_info(l_count).context_id;
2150 l_context_sum1 := p_fdiu_info(l_count).context_sum1;
2151 l_context_sum2 := p_fdiu_info(l_count).context_sum2;
2152
2153 -- Initialise the bind variables to NULL each time.
2154 l_nvalue := NULL;
2155 l_dvalue := NULL;
2156 l_tvalue := NULL;
2157
2158 /*
2159 * Take action, depending on the current usage.
2160 * We are attempting to set a value for l_value.
2161 */
2162 if(l_usage = 'U') then
2163 /* context */
2164
2165 -- Keep count of how many contexts we have processed.
2166 l_context_count := l_context_count + 1;
2167
2168 l_in_index := l_in_index + 1; -- Count index of inputs table.
2169
2170 /* user not allowed to supply NULL value for context */
2171 if(p_inputs(l_in_index).value is null) then
2172 hr_utility.set_message(801, 'FFX02_UIDCOL_MISSING');
2173 hr_utility.set_message_token('1',
2174 p_fmla_info(p_cache_slot).formula_name);
2175 hr_utility.set_message_token('2', l_item_name);
2176 hr_utility.raise_error;
2177 end if;
2178
2179 -- read context value from cache.
2180 l_tvalue := p_ctx_info(l_context_id).tvalue;
2181
2182 -- See if value is either NULL or different from
2183 -- the value the user has supplied.
2184 -- Note the value should only be NULL if this is
2185 -- the first time we have read the value.
2186 if(l_tvalue is null or l_tvalue <> p_inputs(l_in_index).value) then
2187
2188 -- Log changed context.
2189 if g_debug then
2190 ctx_change_debug(l_item_name, l_context_sum1, l_context_sum2,
2191 l_tvalue, p_inputs(l_in_index).value);
2192 end if;
2193
2194 -- Add the current context level to the context total.
2195 if l_context_sum1 <> 0 then
2196 l_context_total1 := l_context_total1 + l_context_sum1;
2197 else
2198 l_context_total2 := l_context_total2 + l_context_sum2;
2199 end if;
2200
2201 --
2202 -- Always set p_ctx_info(l_context_id).tvalue as it is used for the
2203 -- the comparison above.
2204 --
2205 p_ctx_info(l_context_id).tvalue := p_inputs(l_in_index).value;
2206 l_tvalue := p_inputs(l_in_index).value;
2207
2208 --
2209 -- Get the value from the inputs table and write to the contexts
2210 -- cache.
2211 --
2212 if l_data_type = C_DATE then
2213 p_ctx_info(l_context_id).dvalue :=
2214 fnd_date.canonical_to_date(l_tvalue);
2215 elsif l_data_type = C_NUMBER then
2216 p_ctx_info(l_context_id).nvalue := replace(l_tvalue, '.', g_decpoint);
2217 end if;
2218
2219 end if;
2220
2221 --
2222 -- Set the context values for binding.
2223 --
2224 if l_data_type = C_DATE then
2225 l_dvalue := p_ctx_info(l_context_id).dvalue;
2226 elsif l_data_type = C_NUMBER then
2227 l_nvalue := p_ctx_info(l_context_id).nvalue;
2228 else
2229 l_tvalue := p_ctx_info(l_context_id).tvalue;
2230 end if;
2231
2232 -- Have we reached the final context?
2233 if(l_context_count = p_fmla_info(p_cache_slot).context_count) then
2234
2235 -- Have processed last context, see if need to invalidate
2236 -- any database items as a consequence.
2237 invalidate_db_items(l_context_total1, l_context_total2);
2238
2239 end if;
2240
2241 -- Following all this, value should NOT be null.
2242 ff_utils.assert((l_tvalue is not null), 'bind_variables:1');
2243
2244 elsif(l_usage in ('I', 'B')) then
2245 /* An input variable (or input and output). */
2246 l_in_index := l_in_index + 1; -- Count index of inputs table.
2247
2248 -- Convert the values from the inputs table as set by user.
2249 if l_data_type = C_DATE then
2250 l_dvalue := fnd_date.canonical_to_date(p_inputs(l_in_index).value);
2251 elsif l_data_type = C_NUMBER then
2252 l_nvalue := replace(p_inputs(l_in_index).value, '.', g_decpoint);
2253 elsif l_data_type = C_TEXT then
2254 l_tvalue := p_inputs(l_in_index).value;
2255 end if;
2256
2257 elsif(l_usage = 'O') then
2258 /* Output (return) variable. */
2259 -- Simply leave the value as NULL.
2260 null;
2261
2262 elsif(l_usage = 'D') then
2263 /* Database item. */
2264 -- Get the value for database item.
2265 -- If the db item cache is in use, read the value from
2266 -- there, otherwise, set it to NULL.
2267 if(p_use_dbi_cache) then
2268 read_dbi_cache
2269 (p_context_id => l_context_id
2270 ,p_item_name => l_item_name
2271 ,p_data_type => l_data_type
2272 ,p_dvalue => l_dvalue
2273 ,p_nvalue => l_nvalue
2274 ,p_tvalue => l_tvalue
2275 ,p_indicator => l_indic_value
2276 );
2277 else
2278 --
2279 -- The bind variables are already set to NULL. Set the indicator
2280 -- to NULL.
2281 --
2282 l_indic_value := FF_NULL;
2283 end if;
2284 else
2285 -- Houston, we have a problem.
2286 ff_utils.assert(FALSE, 'bind_variables:2');
2287 end if;
2288
2289 /*
2290 * Bind the appropriate variable (and indicator)
2291 * with the value we have obtained.
2292 */
2293 if(l_data_type = C_DATE) then
2294 p_d(l_varpos) := l_dvalue;
2295 elsif(l_data_type = C_NUMBER) then
2296 p_n(l_varpos) := l_nvalue;
2297 elsif(l_data_type = C_TEXT) then
2298 p_t(l_varpos) := l_tvalue;
2299 else
2300 hr_utility.set_message(801, 'FFIC874_UNKNOWN_DATATYPE');
2301 hr_utility.set_message_token('1', l_item_name);
2302 hr_utility.set_message_token('2', l_data_type);
2303 hr_utility.raise_error;
2304 end if;
2305
2306 /*
2307 * Bind the indicator (if appropriate).
2308 */
2309 if(l_indpos <> INVALID_POS) then
2310 -- Set indicator dependent on the value passed in.
2311 if l_indic_value is not null then
2312 p_i(l_indpos) := l_indic_value;
2313 else
2314 if l_dvalue is not null or
2315 l_nvalue is not null or
2316 l_tvalue is not null then
2317 p_i(l_indpos) := FF_NOT_NULL;
2318 else
2319 p_i(l_indpos) := FF_NULL;
2320 end if;
2321 end if;
2322 end if;
2323 end loop;
2324
2325 if g_debug then
2326 ff_utils.exit('bind_variables');
2327 end if;
2328
2329 end bind_variables;
2330
2331 -------------------------------- set_outputs ----------------------------------
2332 /*
2333 NAME
2334 set_outputs
2335 DESCRIPTION
2336 Sets outputs in outputs table from returned values.
2337 NOTES
2338 Called from the run_formula procedure.
2339 */
2340 procedure set_outputs
2341 (
2342 p_cache_slot in binary_integer,
2343 p_fmla_info in fmla_info_t,
2344 p_fdiu_info in fdiu_info_t,
2345 p_d in ff_wrapper_pkg.t_date,
2346 p_n in ff_wrapper_pkg.t_number,
2347 p_t in ff_wrapper_pkg.t_text,
2348 p_i in ff_wrapper_pkg.t_number,
2349 p_outputs in out nocopy ff_exec.outputs_t
2350 ) is
2351 l_first_fdiu binary_integer;
2352 l_last_fdiu binary_integer;
2353 l_count_fdiu binary_integer;
2354 l_out_index binary_integer := 0;
2355 l_varpos binary_integer;
2356 l_indpos binary_integer;
2357 l_indic_value binary_integer;
2358 l_usage varchar2(1);
2359 l_data_type varchar2(6);
2360 l_dvalue date;
2361 l_nvalue number;
2362 l_value varchar2(255); -- matches ff_exec.FF_BIND_LEN
2363 begin
2364
2365 if g_debug then
2366 ff_utils.entry('set_outputs');
2367 end if;
2368
2369 /*
2370 * Set the output table from returned values.
2371 */
2372 l_first_fdiu := p_fmla_info(p_cache_slot).first_fdiu;
2373 l_last_fdiu := l_first_fdiu + p_fmla_info(p_cache_slot).fdiu_count - 1;
2374
2375 for l_count_fdiu in l_first_fdiu..l_last_fdiu loop
2376
2377 -- We only wish to process anything for
2378 -- output variables or database items.
2379 if(p_fdiu_info(l_count_fdiu).usage in ('O', 'B', 'D')) then
2380
2381 -- Set up some locals for convenience.
2382 l_varpos := p_fdiu_info(l_count_fdiu).varpos;
2383 l_indpos := p_fdiu_info(l_count_fdiu).indpos;
2384 l_usage := p_fdiu_info(l_count_fdiu).usage;
2385 l_data_type := p_fdiu_info(l_count_fdiu).data_type;
2386
2387 /* Get the variable value. */
2388 if l_usage <> 'D' then
2389 if(l_data_type = C_DATE) then
2390 -- Dates converted to apps Canonical format.
2391 l_value := fnd_date.date_to_canonical(p_d(l_varpos));
2392 elsif(l_data_type = C_NUMBER) then
2393 -- Numbers converted to canonical format.
2394 l_value := replace(to_char(p_n(l_varpos)),g_decpoint,'.');
2395 else
2396 l_value := p_t(l_varpos);
2397 end if;
2398 else
2399 if(l_data_type = C_DATE) then
2400 l_dvalue := p_d(l_varpos);
2401 l_nvalue := NULL;
2402 l_value := NULL;
2403 elsif(l_data_type = C_NUMBER) then
2404 l_nvalue := p_n(l_varpos);
2405 l_dvalue := NULL;
2406 l_value := NULL;
2407 else
2408 l_value := p_t(l_varpos);
2409 l_dvalue := NULL;
2410 l_nvalue := NULL;
2411 end if;
2412 end if;
2413
2414 /* Get the indicator value. */
2415 l_indic_value := p_i(l_indpos);
2416
2417 /* Process the indicator. */
2418 if(l_indic_value = FF_NULL) then
2419 -- The indicator shows we need to set the value to null.
2420 l_value := NULL;
2421 l_dvalue := NULL;
2422 l_nvalue := NULL;
2423 end if;
2424
2425 /* process dependent on the usage */
2426 if(l_usage in ('O', 'B')) then
2427
2428 l_out_index := l_out_index + 1; -- Where are we in output table?
2429
2430 -- The variable is an output type, so set output table entry.
2431 p_outputs(l_out_index).value := l_value;
2432
2433 else /* usage is 'D' */
2434
2435 --
2436 -- Database item was returned
2437 -- If the database item was not defaulted, we want to write
2438 -- the returned value to the db item cache. If it was defaulted
2439 -- then, we want to update the indicator value in the cache.
2440 --
2441 if(l_indic_value = FF_WAS_DEFAULTED) then
2442 l_value := NULL;
2443 l_nvalue := NULL;
2444 l_dvalue := NULL;
2445 end if;
2446
2447 write_dbi_cache
2448 (p_context_id => p_fdiu_info(l_count_fdiu).context_id
2449 ,p_item_name => p_fdiu_info(l_count_fdiu).name
2450 ,p_data_type => l_data_type
2451 ,p_dvalue => l_dvalue
2452 ,p_nvalue => l_nvalue
2453 ,p_tvalue => l_value
2454 ,p_force_write => TRUE
2455 ,p_indicator => l_indic_value
2456 );
2457
2458 end if;
2459
2460 end if;
2461
2462 end loop;
2463
2464 if g_debug then
2465 ff_utils.exit('set_outputs');
2466 end if;
2467
2468 exception
2469 when others then
2470 --
2471 -- NOCOPY change. The issue is to avoid the FF Outputs having partially
2472 -- filled-in values now that FF_EXEC.RUN_FORMULA is passing them in
2473 -- by reference i.e. using NOCOPY.
2474 -- Solution: Set the outputs to NULL.
2475 --
2476 l_out_index := 0;
2477 for l_count_fdiu in l_first_fdiu..l_last_fdiu loop
2478 --
2479 -- Only interested in values that get set on output. DBI behaviour is
2480 -- unchanged before because the code has used NOCOPY internally for
2481 -- some time.
2482 --
2483 if(p_fdiu_info(l_count_fdiu).usage in ('O', 'B')) then
2484 l_out_index := l_out_index + 1;
2485 p_outputs(l_out_index).value := null;
2486 end if;
2487 end loop;
2488 raise;
2489 end set_outputs;
2490
2491 /*---------------------------------------------------------------------------*/
2492 /*------------------ global functions and procedures ------------------------*/
2493 /*---------------------------------------------------------------------------*/
2494
2495 ------------------------------- reset_caches ----------------------------------
2496 /*
2497 NAME
2498 reset_caches
2499 DESCRIPTION
2500 Resets the internal caches to their initial states.
2501 NOTES
2502 */
2503 procedure reset_caches is
2504 begin
2505 g_fmla_lookups.delete;
2506 if g_inited then
2507 g_fmla_info.delete;
2508 end if;
2509 g_inited := true;
2510 g_fmla_info := fmla_info_t();
2511 g_lru_slot := 1;
2512 g_free_fdiu.delete;
2513 g_fdiu_info.delete;
2514 g_hash_info.delete;
2515 g_dbi_info.delete;
2516 g_ctx_info.delete;
2517 g_next_dbi_index := 1;
2518
2519 g_route_ctx_sums.delete;
2520 g_ctx_levels1 := 0;
2521 g_ctx_levels2 := 0;
2522
2523 --
2524 -- Set debugging profile.
2525 --
2526 check_profile_debug;
2527
2528 --
2529 -- Set the USE_FF_WRAPPER flag.
2530 --
2531 set_use_ff_wrapper;
2532
2533 --
2534 -- Set the cache size.
2535 --
2536 set_cache_size;
2537 end reset_caches;
2538
2539 ---------------------------- init_formula -------------------------------------
2540 /*
2541 NAME
2542 init_formula
2543 DESCRIPTION
2544 Initialises data structures for a specific formula.
2545 NOTES
2546 Very straight-forward. Is really a cover for the formula
2547 information cache load function.
2548
2549 As far as the user is concerned, the reason for calling
2550 this procedure is to obtain information about the inputs
2551 and outputs required by the formula.
2552 */
2553
2554 procedure init_formula
2555 (
2556 p_formula_id in number,
2557 p_effective_date in date,
2558 p_inputs in out nocopy ff_exec.inputs_t,
2559 p_outputs in out nocopy ff_exec.outputs_t
2560 ) is
2561 l_count binary_integer;
2562 l_first_fdiu binary_integer;
2563 l_last_fdiu binary_integer;
2564 l_in_index binary_integer := 0;
2565 l_out_index binary_integer := 0;
2566 l_cache_slot binary_integer;
2567 begin
2568 /* Set decimal point character. */
2569 g_decpoint := substr(to_char(1.1),2,1);
2570
2571 g_debug := hr_utility.debug_enabled;
2572 if g_debug then
2573 ff_utils.entry('init_formula');
2574 end if;
2575
2576 if g_debug then
2577 hr_utility.trace('fmla cache size: ' || g_exec_info.fmla_cache_size);
2578 end if;
2579
2580 -- Load formula information into cache if necessary.
2581 -- Global variables are passed to aid modularity.
2582 load_formula (p_formula_id, p_effective_date, g_exec_info,
2583 g_fmla_lookups, g_fmla_info, g_lru_slot,
2584 g_fdiu_info, g_ctx_info);
2585 l_cache_slot := g_exec_info.cache_slot;
2586
2587 /*
2588 * Move the inputs and outputs into the table
2589 */
2590 p_inputs.delete; -- must start with empty inputs table.
2591 p_outputs.delete; -- must start with empty outputs table.
2592
2593 -- Get parameters for loop
2594 l_first_fdiu := g_fmla_info(l_cache_slot).first_fdiu;
2595 l_last_fdiu := l_first_fdiu + g_fmla_info(l_cache_slot).fdiu_count - 1;
2596
2597 -- Loop round the appropriate fdiu rows for the formula.
2598 -- Note that the index numbers for the input and output tables
2599 -- will start from 1 and be contiguous.
2600 for l_count in l_first_fdiu..l_last_fdiu loop
2601 if (g_fdiu_info(l_count).usage in ('I', 'U', 'B')) then
2602 -- Entry for inputs table.
2603 l_in_index := l_in_index + 1;
2604 p_inputs(l_in_index).name := g_fdiu_info(l_count).name;
2605 p_inputs(l_in_index).datatype := g_fdiu_info(l_count).data_type;
2606
2607 -- Set up the class for input.
2608 if(g_fdiu_info(l_count).usage in ('I', 'B')) then
2609 p_inputs(l_in_index).class := 'INPUT';
2610 else
2611 p_inputs(l_in_index).class := 'CONTEXT';
2612 end if;
2613 end if;
2614
2615 if (g_fdiu_info(l_count).usage in ('O', 'B')) then
2616 -- Entry for output table.
2617 l_out_index := l_out_index + 1;
2618 p_outputs(l_out_index).name := g_fdiu_info(l_count).name;
2619 p_outputs(l_out_index).datatype := g_fdiu_info(l_count).data_type;
2620 end if;
2621 end loop;
2622
2623 /*
2624 * Record the number of rows in the inputs and
2625 * outputs tables. This allows the run time
2626 * system to perform a sanity check later on.
2627 */
2628 g_exec_info.input_rows := p_inputs.count;
2629 g_exec_info.output_rows := p_outputs.count;
2630
2631 if g_debug then
2632 ff_utils.exit('init_formula');
2633 end if;
2634
2635 end init_formula;
2636
2637 ------------------------------ run_formula ------------------------------------
2638 /*
2639 NAME
2640 run_formula
2641 DESCRIPTION
2642 Uses data structures built up to execute Fast Formula.
2643 NOTES
2644 <none>
2645 */
2646
2647 procedure run_formula
2648 (
2649 p_inputs in ff_exec.inputs_t,
2650 p_outputs in out nocopy ff_exec.outputs_t,
2651 p_use_dbi_cache in boolean default true
2652 ) is
2653 l_formula_id number;
2654 l_cache_slot binary_integer;
2655 l_line_number number := 0;
2656 l_err_number number := 0;
2657 l_error_message varchar2(255) := null;
2658 l_rows_processed number;
2659 l_first_fdiu binary_integer;
2660 l_last_fdiu binary_integer;
2661 l_count_fdiu binary_integer;
2662 l_fmla_name varchar2(80);
2663 l_d ff_wrapper_pkg.t_date;
2664 l_n ff_wrapper_pkg.t_number;
2665 l_t ff_wrapper_pkg.t_text;
2666 l_i ff_wrapper_pkg.t_number;
2667 begin
2668 g_debug := hr_utility.debug_enabled;
2669 if g_debug then
2670 ff_utils.entry('run_formula');
2671 end if;
2672
2673 -- Check that the execution engine is initialised.
2674 if(g_exec_info.formula_id is null) then
2675 hr_utility.set_message(801, 'FFPLX03_NO_INIT');
2676 hr_utility.raise_error;
2677 end if;
2678
2679 -- Sanity checks on the number of rows in the
2680 -- inputs and outputs tables. This helps to
2681 -- ensure the caller hasn't messed with them.
2682 ff_utils.assert((g_exec_info.input_rows = p_inputs.count), 'run_formula:1');
2683 ff_utils.assert((g_exec_info.output_rows = p_outputs.count), 'run_formula:2');
2684
2685 /*
2686 * Set up a few useful variables.
2687 */
2688 l_cache_slot := g_exec_info.cache_slot;
2689 l_fmla_name := g_fmla_info(l_cache_slot).formula_name;
2690
2691 -- Show the inputs.
2692 if g_debug then
2693 io_table_debug(p_inputs, p_outputs, 'INPUT');
2694 end if;
2695
2696 -- DBI cache debug.
2697 if g_debug then
2698 dbi_cache_debug(g_ctx_info, g_dbi_info, g_hash_info);
2699 end if;
2700
2701 /*
2702 * Call routine to bind variables from user supplied info.
2703 */
2704 bind_variables(l_cache_slot, p_inputs, p_outputs, g_fmla_info,
2705 g_fdiu_info, g_ctx_info, l_d, l_n, l_t, l_i,
2706 p_use_dbi_cache);
2707
2708 /*
2709 * Execute PLSQL block.
2710 */
2711
2712 -- Actually run the formula.
2713 -- Use local exception block to catch any oracle error.
2714 if g_exec_info.use_ff_wrapper then
2715 begin
2716 ff_wrapper_main_pkg.formula
2717 (p_formula_name => l_fmla_name
2718 ,p_ff_package_name => g_fmla_info(l_cache_slot).package_name
2719 ,p_d => l_d
2720 ,p_n => l_n
2721 ,p_t => l_t
2722 ,p_i => l_i
2723 ,p_fferln => l_line_number
2724 ,p_ffercd => l_err_number
2725 ,p_ffermt => l_error_message
2726 );
2727 exception
2728 when CANNOT_FIND_PROG_UNIT then
2729 -- Wrapper package body needs to be regenerated.
2730 hr_utility.set_message(802, 'FF_33186_GENERATE_WRAPPER');
2731 hr_utility.set_message_token('1', l_fmla_name);
2732 hr_utility.raise_error;
2733
2734 when others then
2735 -- Getting an unhandled exception from PLSQL.
2736 hr_utility.set_message(801, 'FFX18_PLSQL_ERROR');
2737 hr_utility.set_message_token('1', l_fmla_name);
2738 hr_utility.set_message_token('2', sqlerrm);
2739 hr_utility.raise_error;
2740
2741 end;
2742 else
2743 begin
2744 ff_wrapper_pkg.g_d := l_d;
2745 ff_wrapper_pkg.g_i := l_i;
2746 ff_wrapper_pkg.g_n := l_n;
2747 ff_wrapper_pkg.g_t := l_t;
2748 ff_wrapper_pkg.g_fferln := null;
2749 ff_wrapper_pkg.g_ffercd := null;
2750 ff_wrapper_pkg.g_ffermt := null;
2751 execute immediate
2752 'begin ' || g_fmla_info(l_cache_slot).package_name || '.formula; end;';
2753 exception
2754 when bad_plsql then
2755 hr_utility.set_message(801,'FFX22J_FORMULA_NOT_FOUND');
2756 hr_utility.set_message_token('1',l_fmla_name);
2757 hr_utility.raise_error;
2758
2759 when others then
2760 -- Getting an unhandled exception from PLSQL.
2761 hr_utility.set_message(801, 'FFX18_PLSQL_ERROR');
2762 hr_utility.set_message_token('1', l_fmla_name);
2763 hr_utility.set_message_token('2', sqlerrm);
2764 hr_utility.raise_error;
2765 end;
2766 --
2767 l_d := ff_wrapper_pkg.g_d;
2768 l_i := ff_wrapper_pkg.g_i;
2769 l_n := ff_wrapper_pkg.g_n;
2770 l_t := ff_wrapper_pkg.g_t;
2771 l_line_number := ff_wrapper_pkg.g_fferln;
2772 l_err_number := ff_wrapper_pkg.g_ffercd;
2773 l_error_message := ff_wrapper_pkg.g_ffermt;
2774 end if;
2775
2776 /*
2777 * Check for specific error conditions.
2778 */
2779 if(l_err_number > 0) then
2780
2781 -- Precise error detected in plsql, set up tokens.
2782 if(l_err_number = 1) then
2783 hr_utility.set_message(801, 'FFX00_LOCAL_NOT_INITIALIZED');
2784 elsif(l_err_number = 2) then
2785 hr_utility.set_message(801, 'FFX00_ZERO_DIVISION');
2786 elsif(l_err_number = 3) then
2787 hr_utility.set_message(801, 'FFX00_DATA_NOT_FOUND');
2788 elsif(l_err_number = 4) then
2789 hr_utility.set_message(801, 'FFX00_TOO_MANY_ROWS');
2790 elsif(l_err_number = 5) then
2791 hr_utility.set_message(801, 'FFX00_VALUE_RANGE_ERROR');
2792 elsif(l_err_number = 6) then
2793 hr_utility.set_message(801, 'FFX00_INVALID_NUMBER');
2794 elsif(l_err_number = 7) then
2795 hr_utility.set_message(801, 'FFX00_NULL_VALUE');
2796 elsif(l_err_number = 8) then
2797 hr_utility.set_message(801, 'FFX00_UDF_ERROR');
2798 else
2799 hr_utility.set_message(801, 'FFPLX02_UNKNOWN_PLSQL_ERR');
2800 hr_utility.set_message_token('ERROR', l_err_number);
2801 hr_utility.raise_error;
2802 end if;
2803
2804 hr_utility.set_message_token('1', l_fmla_name);
2805 hr_utility.set_message_token('2', l_line_number);
2806 hr_utility.set_message_token('3', l_error_message);
2807 hr_utility.raise_error;
2808
2809 elsif(l_err_number < 0) then
2810
2811 -- Oracle error has been trapped by Formula.
2812 hr_utility.set_message(801, 'FFX18_ORA_PLSQL');
2813 hr_utility.set_message_token('1', l_fmla_name);
2814 hr_utility.set_message_token('2', l_err_number);
2815 hr_utility.set_message_token('3', l_line_number);
2816 hr_utility.raise_error;
2817
2818 end if;
2819
2820 /*
2821 * Set values in the outputs table and
2822 * write to db item cache if necessary.
2823 */
2824 set_outputs
2825 ( l_cache_slot, g_fmla_info, g_fdiu_info, l_d, l_n, l_t, l_i, p_outputs);
2826
2827 -- Show the contents of inputs and outputs table.
2828 if g_debug then
2829 io_table_debug(p_inputs, p_outputs, 'OUTPUT');
2830 end if;
2831
2832 /*
2833 * Finished!
2834 * Now the user should have all his values in the outputs
2835 * table and be able to process them.
2836 */
2837
2838 if g_debug then
2839 ff_utils.exit('run_formula');
2840 end if;
2841
2842 end run_formula;
2843
2844 /*
2845 * Global initialisation section.
2846 */
2847 begin
2848 --
2849 -- Set the formula caches to their initial values.
2850 --
2851 reset_caches;
2852 end ff_exec;