DBA Data[Home] [Help]

PACKAGE BODY: APPS.HRI_OPL_POSH

Source


1 PACKAGE BODY hri_opl_posh AS
2 /* $Header: hrioposh.pkb 120.1 2005/06/08 02:53:23 anmajumd noship $ */
3 
4 /******************************************************************************/
5 /*                                                                            */
6 /* OUTLINE / DEFINITIONS                                                      */
7 /*                                                                            */
8 /* A chain is defined for a position as a list starting with the position     */
9 /* which contains and successive higher level positions finishing with the    */
10 /* highest level (top) position.                                              */
11 /*                                                                            */
12 /* IMPLEMENTATION LOGIC                                                       */
13 /*                                                                            */
14 /* The position hierarchy table is populated by carrying out the following    */
15 /* steps:                                                                     */
16 /*                                                                            */
17 /*  1) Empty out existing table                                               */
18 /*                                                                            */
19 /*  2) Loop through a view containing top positions for each position         */
20 /*     hierarchy version                                                      */
21 /*                                                                            */
22 /*    i) Insert top position chain into the position hierarchy table          */
23 /*   ii) Insert chain for all positions in that position hierarchy version    */
24 /*       making use of the data structure to avoid recalculating the same     */
25 /*       information twice                                                    */
26 /*                                                                            */
27 /*  3) Global structures are used to:                                         */
28 /*                                                                            */
29 /*    i) Bulk fetch the main loop                                             */
30 /*   ii) Bulk insert the chains into the hierarchy table                      */
31 /*  iii) Store information about the current chain being processed            */
32 /*   iv) Keep a note of which chains have been processed on a particular      */
33 /*       date to avoid re-processing the same information                     */
34 /*    v) Keep a note of the date each chain starts, so that the next time     */
35 /*       a chain is processed (on an earlier date) the end date is known      */
36 /*   vi) Store the terminated assignment status types so that it is quick to  */
37 /*       find out which are invalid at insert time                            */
38 /*                                                                            */
39 /******************************************************************************/
40 
41 /* Information to be held for each link in a chain */
42 TYPE g_link_record_type IS RECORD
43   (business_group_id       per_pos_structure_elements.business_group_id%TYPE
44   ,position_id             per_pos_structure_elements.parent_position_id%TYPE);
45 
46 /* Table type to hold information about the current chain */
47 TYPE g_chain_type IS TABLE OF g_link_record_type INDEX BY BINARY_INTEGER;
48 
49 /* Global structure holding information about the current chain */
50 g_crrnt_chain              g_chain_type;
51 
52 /* Simple table types */
53 TYPE g_date_tab_type IS TABLE OF DATE INDEX BY BINARY_INTEGER;
54 TYPE g_number_tab_type IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
55 TYPE g_varchar2_tab_type IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
56 
57 /* PLSQL table of tables representing database table */
58 g_dbtab_pst_id             g_number_tab_type;
59 g_dbtab_prm_flg            g_varchar2_tab_type;
60 g_dbtab_psv_id             g_number_tab_type;
61 g_dbtab_vno_id             g_number_tab_type;
62 g_dbtab_bgr_id             g_number_tab_type;
63 g_dbtab_sup_pos_id         g_number_tab_type;
64 g_dbtab_sup_level          g_number_tab_type;
65 g_dbtab_sub_pos_id         g_number_tab_type;
66 g_dbtab_sub_level          g_number_tab_type;
67 g_dbtab_sub_rlt_lvl        g_number_tab_type;
68 g_dbtab_start_date         g_date_tab_type;
69 g_dbtab_end_date           g_date_tab_type;
70 
71 /* Global variables for current position structure version */
72 g_position_structure_id      NUMBER;
73 g_pos_structure_version_id   NUMBER;
74 g_version_number             NUMBER;
75 g_effective_start_date       NUMBER;
76 g_effective_end_date         NUMBER;
77 
78 /* Global tables for bulk fetch */
79 g_fetch_top_pos_id      g_number_tab_type;
80 g_fetch_psv_id          g_number_tab_type;
81 g_fetch_pst_id          g_number_tab_type;
82 g_fetch_vno_id          g_number_tab_type;
83 g_fetch_prm_flg         g_varchar2_tab_type;
84 g_fetch_start_dt        g_date_tab_type;
85 g_fetch_end_dt          g_date_tab_type;
86 g_fetch_bgr_id          g_number_tab_type;
87 
88 g_stored_rows_to_insert    PLS_INTEGER;  -- Number of row to insert
89 
90 /* Set to true to output to a concurrent log file */
91 g_conc_request_flag       BOOLEAN := FALSE;
92 
93 /* Number of rows bulk processed at a time */
94 g_chunk_size              PLS_INTEGER;
95 
96 /* End of time date */
97 g_end_of_time             DATE := hr_general.end_of_time;
98 
99 /******************************************************************************/
100 /* Inserts row into concurrent program log when the g_conc_request_flag has   */
101 /* been set to TRUE, otherwise does nothing                                   */
102 /******************************************************************************/
103 PROCEDURE output(p_text  VARCHAR2)
104   IS
105 
106 BEGIN
107 
108 /* Write to the concurrent request log if called from a concurrent request */
109   IF (g_conc_request_flag = TRUE) THEN
110 
111    /* Put text to log file */
112     fnd_file.put_line(FND_FILE.log, p_text);
113 
114   END IF;
115 
116 END output;
117 
118 /******************************************************************************/
119 /* Recovers rows to insert when an exception occurs                           */
120 /******************************************************************************/
121 PROCEDURE recover_insert_rows IS
122 
123 BEGIN
124   -- loop through rows still to insert one at a time
125   FOR i IN 1..g_stored_rows_to_insert LOOP
126 
127     -- Trap unique constraint errors
128     BEGIN
129 
130       INSERT INTO hri_cs_posh
131         (position_structure_id
132         ,primary_hierarchy_flag_code
133         ,pos_structure_version_id
134         ,version_number
135         ,business_group_id
136         ,sup_position_id
137         ,sup_level
138         ,sub_position_id
139         ,sub_level
140         ,sub_relative_level
141         ,effective_start_date
142         ,effective_end_date)
143           VALUES
144             (g_dbtab_pst_id(i)
145             ,g_dbtab_prm_flg(i)
146             ,g_dbtab_psv_id(i)
147             ,g_dbtab_vno_id(i)
148             ,g_dbtab_bgr_id(i)
149             ,g_dbtab_sup_pos_id(i)
150             ,g_dbtab_sup_level(i)
151             ,g_dbtab_sub_pos_id(i)
152             ,g_dbtab_sub_level(i)
153             ,g_dbtab_sub_rlt_lvl(i)
154             ,g_dbtab_start_date(i)
155             ,g_dbtab_end_date(i));
156 
157     EXCEPTION
158       WHEN OTHERS THEN
159 
160       /* Probable overlap on date tracked assignment rows */
161       output('Single insert error: ' || to_char(g_dbtab_sub_pos_id(i)) ||
162              ' - ' || to_char(g_dbtab_sup_pos_id(i)));
163       output('Inserting date range: ' ||
164               to_char(g_dbtab_start_date(i),'DD-MON-YYYY') || ' - ' ||
165               to_char(g_dbtab_end_date(i),'DD-MON-YYYY'));
166       output(sqlerrm);
167       output(sqlcode);
168 
169     END;
170 
171   END LOOP;
172 
173   -- commit
174   commit;
175 
176 END recover_insert_rows;
177 
178 /******************************************************************************/
179 /* Bulk inserts rows from global temporary table to database table            */
180 /******************************************************************************/
181 PROCEDURE bulk_insert_rows IS
182 
183 BEGIN
184   -- insert chunk of rows
185   FORALL i IN 1..g_stored_rows_to_insert
186     INSERT INTO hri_cs_posh
187         (position_structure_id
188         ,primary_hierarchy_flag_code
189         ,pos_structure_version_id
190         ,version_number
191         ,business_group_id
192         ,sup_position_id
193         ,sup_level
194         ,sub_position_id
195         ,sub_level
196         ,sub_relative_level
197         ,effective_start_date
198         ,effective_end_date)
199           VALUES
200             (g_dbtab_pst_id(i)
201             ,g_dbtab_prm_flg(i)
202             ,g_dbtab_psv_id(i)
203             ,g_dbtab_vno_id(i)
204             ,g_dbtab_bgr_id(i)
205             ,g_dbtab_sup_pos_id(i)
206             ,g_dbtab_sup_level(i)
207             ,g_dbtab_sub_pos_id(i)
208             ,g_dbtab_sub_level(i)
209             ,g_dbtab_sub_rlt_lvl(i)
210             ,g_dbtab_start_date(i)
211             ,g_dbtab_end_date(i));
212   -- commit the chunk of rows
213   COMMIT;
214 EXCEPTION
215   WHEN OTHERS THEN
216 
217 /* Unique constraint error */
218   rollback;
219   recover_insert_rows;
220 
221 END bulk_insert_rows;
222 
223 /******************************************************************************/
224 /* Inserts row into global temporary table                                    */
225 /******************************************************************************/
226 PROCEDURE insert_row( p_business_group_id       IN NUMBER
227                     , p_sup_position_id         IN NUMBER
228                     , p_sup_level               IN NUMBER
229                     , p_sub_position_id         IN NUMBER
230                     , p_sub_level               IN NUMBER
231                     , p_index                   IN NUMBER ) IS
232 
233 BEGIN
234   -- increment the index
235   g_stored_rows_to_insert := g_stored_rows_to_insert + 1;
236   -- set the table structures
237   g_dbtab_pst_id(g_stored_rows_to_insert)       := g_fetch_pst_id(p_index);
238   g_dbtab_prm_flg(g_stored_rows_to_insert)      := g_fetch_prm_flg(p_index);
239   g_dbtab_psv_id(g_stored_rows_to_insert)       := g_fetch_psv_id(p_index);
240   g_dbtab_vno_id(g_stored_rows_to_insert)       := g_fetch_vno_id(p_index);
241   g_dbtab_bgr_id(g_stored_rows_to_insert)       := p_business_group_id;
242   g_dbtab_sup_pos_id(g_stored_rows_to_insert)   := p_sup_position_id;
243   g_dbtab_sup_level(g_stored_rows_to_insert)    := p_sup_level;
244   g_dbtab_sub_pos_id(g_stored_rows_to_insert)   := p_sub_position_id;
245   g_dbtab_sub_level(g_stored_rows_to_insert)    := p_sub_level;
246   g_dbtab_sub_rlt_lvl(g_stored_rows_to_insert)  := p_sub_level - p_sup_level;
247   g_dbtab_start_date(g_stored_rows_to_insert)   := g_fetch_start_dt(p_index);
248   g_dbtab_end_date(g_stored_rows_to_insert)     := g_fetch_end_dt(p_index);
249 END insert_row;
250 
251 /******************************************************************************/
252 /* Updates all positions in the position hierarchy version starting with the  */
253 /* top position.                                                              */
254 /******************************************************************************/
255 PROCEDURE calculate_chains( p_index        IN NUMBER ) IS
256 
257 /* Cursor picks out all positions in the position structure */
258 /* This cursor MUST return rows in the default order */
259   CURSOR positions_csr IS
260   SELECT
261    hier.business_group_id         business_group_id
262   ,hier.subordinate_position_id   position_id
263   ,LEVEL+1                        actual_level
264   FROM (SELECT
265         pse.business_group_id
266        ,pse.subordinate_position_id
267        ,pse.parent_position_id
268        FROM
269         per_pos_structure_elements   pse
270        WHERE pse.pos_structure_version_id = g_fetch_psv_id(p_index))  hier
271   START WITH hier.parent_position_id = g_fetch_top_pos_id(p_index)
272   CONNECT BY PRIOR hier.subordinate_position_id = parent_position_id;
273 /******************************/
274 /* DO NOT ADD ORDER BY CLAUSE */
275 /******************************/
276 
277   l_pos_lvl          PLS_INTEGER;
278 
279 BEGIN
280 
281 /* Store details for top position */
282   g_crrnt_chain(1).business_group_id := g_fetch_bgr_id(p_index);
283   g_crrnt_chain(1).position_id       := g_fetch_top_pos_id(p_index);
284 
285       /* Insert chain */
286         insert_row
287           (p_business_group_id     => g_crrnt_chain(1).business_group_id
288           ,p_sup_position_id       => g_crrnt_chain(1).position_id
289           ,p_sup_level             => 1
290           ,p_sub_position_id       => g_crrnt_chain(1).position_id
291           ,p_sub_level             => 1
292           ,p_index                 => p_index);
293 
294 /* Loop through positions in position hierarchy veresion */
295   FOR pos_rec IN positions_csr LOOP
296 
297     l_pos_lvl := pos_rec.actual_level;
298 
299     g_crrnt_chain(l_pos_lvl).business_group_id := pos_rec.business_group_id;
300     g_crrnt_chain(l_pos_lvl).position_id       := pos_rec.position_id;
301 
302     /* Loop through links in (stored) chain of positions */
303       FOR l_sup_lvl IN 1..l_pos_lvl LOOP
304 
305       /* Insert chain */
306         insert_row
307           (p_business_group_id     => g_crrnt_chain(l_sup_lvl).business_group_id
308           ,p_sup_position_id       => g_crrnt_chain(l_sup_lvl).position_id
309           ,p_sup_level             => l_sup_lvl
310           ,p_sub_position_id       => g_crrnt_chain(l_pos_lvl).position_id
311           ,p_sub_level             => l_pos_lvl
312           ,p_index                 => p_index);
313 
314       END LOOP; -- Links in stored chain
315 
316   END LOOP;  -- Positions in hierarchy version
317 
318 EXCEPTION
319   WHEN OTHERS THEN
320 
321 /* ORA 01436 - loop in tree walk */
322   IF (SQLCODE = -1436) THEN
323     output('Loop found for position id:  ' ||
324             to_char(g_fetch_top_pos_id(p_index)));
325   ELSE
326 /* Some other error */
327     RAISE;
328   END IF;
329 
330 END calculate_chains;
331 
332 /******************************************************************************/
333 /* Loops through position structure versions                                  */
334 /******************************************************************************/
335 PROCEDURE collect_pos_structures IS
336 
337 /* Pick out all position structure versions and their top positions */
338   CURSOR hrchy_version_csr IS
339   SELECT DISTINCT
340    pse.parent_position_id
341   ,psv.pos_structure_version_id
342   ,psv.position_structure_id
343   ,psv.version_number
344   ,pst.primary_position_flag
345   ,psv.date_from
346   ,NVL(psv.date_to,g_end_of_time)
347   ,psv.business_group_id
348   FROM
349    per_pos_structure_elements pse
350   ,per_pos_structure_versions psv
351   ,per_position_structures    pst
352   WHERE psv.pos_structure_version_id = pse.pos_structure_version_id
353   AND pst.position_structure_id = psv.position_structure_id
354   AND pst.primary_position_flag = 'Y'
355   AND NOT EXISTS
356     (SELECT NULL
357      FROM per_pos_structure_elements pse2
358      WHERE pse2.pos_structure_version_id = pse.pos_structure_version_id
359      AND pse2.subordinate_position_id = pse.parent_position_id);
360 
361   l_return_code          PLS_INTEGER;
362   l_exit_main_loop       BOOLEAN := FALSE;
363   l_rows_fetched         PLS_INTEGER := g_chunk_size;
364 
365 BEGIN
366   -- initialise the g_stored_rows_to_insert
367   g_stored_rows_to_insert := 0;
368   -- open main cursor
369   OPEN hrchy_version_csr;
370   <<main_loop>>
371   LOOP
372     -- bulk fetch rows limit the fetch to value of g_chunk_size
373     FETCH hrchy_version_csr
374     BULK COLLECT INTO
375           g_fetch_top_pos_id,
376           g_fetch_psv_id,
377           g_fetch_pst_id,
378           g_fetch_vno_id,
379           g_fetch_prm_flg,
380           g_fetch_start_dt,
381           g_fetch_end_dt,
382           g_fetch_bgr_id
383     LIMIT g_chunk_size;
384     -- check to see if the last row has been fetched
385     IF hrchy_version_csr%NOTFOUND THEN
386       -- last row fetched, set exit loop flag
387       l_exit_main_loop := TRUE;
388       -- do we have any rows to process?
389       l_rows_fetched := MOD(hrchy_version_csr%ROWCOUNT,g_chunk_size);
390       -- note: if l_rows_fetched > 0 then more rows are required to be
391       -- processed and the l_rows_fetched will contain the exact number of
392       -- rows left to process
393       IF l_rows_fetched = 0 THEN
394         -- no more rows to process so exit loop
395         EXIT main_loop;
396       END IF;
397     END IF;
398 
399     -- Loop through position hierarchy versions
400     FOR i IN 1..l_rows_fetched LOOP
401 
402       calculate_chains( p_index => i );
403 
404     END LOOP;
405     -- bulk insert rows processed so far
406     bulk_insert_rows;
407     -- reset the index
408     g_stored_rows_to_insert := 0;
409     -- exit loop if required
410     IF l_exit_main_loop THEN
411       EXIT main_loop;
412     END IF;
413   END LOOP;
414   CLOSE hrchy_version_csr;
415 EXCEPTION
416   WHEN OTHERS THEN
417     -- unexpected error has occurred so close down
418     -- main bulk cursor if it is open
419     IF hrchy_version_csr%ISOPEN THEN
420       CLOSE hrchy_version_csr;
421     END IF;
422     -- re-raise error
423     RAISE;
424 END collect_pos_structures;
425 
426 /******************************************************************************/
427 /* Main entry point to reload the position hierarchy table                    */
428 /******************************************************************************/
429 PROCEDURE Load_all_positions( p_chunk_size    IN NUMBER ) IS
430 
431   l_sql_stmt      VARCHAR2(2000);
432   l_dummy1        VARCHAR2(2000);
433   l_dummy2        VARCHAR2(2000);
434   l_schema        VARCHAR2(400);
435 
436 BEGIN
437 
438 /* Set chunk size */
439   g_chunk_size := p_chunk_size;
440 
441 /* Time at start */
442   output('PL/SQL Start:   ' || to_char(sysdate,'HH24:MI:SS'));
443 
444 /* Get HRI schema name - get_app_info populates l_schema */
445   IF fnd_installation.get_app_info('HRI',l_dummy1, l_dummy2, l_schema) THEN
446 
447   /* Empty out position hierarchy table */
448     l_sql_stmt := 'TRUNCATE TABLE ' || l_schema || '.HRI_CS_POSH';
449     EXECUTE IMMEDIATE(l_sql_stmt);
450 
451   /* Write timing information to log */
452     output('Truncated Position Hierarchy table:   '  ||
453            to_char(sysdate,'HH24:MI:SS'));
454 
455   /* Insert new position hierarchy records */
456     collect_pos_structures;
457 
458   /* Write timing information to log */
459     output('Re-populated Position Hierarchy table:  '  ||
460            to_char(sysdate,'HH24:MI:SS'));
461 
462   /* Gather index stats */
463     fnd_stats.gather_table_stats(l_schema, 'HRI_CS_POSH');
464 
465   /* Write timing information to log */
466     output('Gathered stats:   '  ||
467            to_char(sysdate,'HH24:MI:SS'));
468 
469   END IF;
470 
471 END Load_all_positions;
472 
473 /******************************************************************************/
474 /* Entry point to be called from the concurrent manager                       */
475 /******************************************************************************/
476 PROCEDURE load_all_positions( errbuf          OUT NOCOPY VARCHAR2,
477                               retcode         OUT NOCOPY VARCHAR2,
478                               p_chunk_size    IN NUMBER )
479 
480 IS
481 
482 BEGIN
483 
484 /* Enable output to concurrent request log */
485   g_conc_request_flag := TRUE;
486 
487 /* Call main function */
488   load_all_positions
489     (p_chunk_size => p_chunk_size);
490 
491 EXCEPTION
492   WHEN OTHERS THEN
493     errbuf := SQLERRM;
494     retcode := SQLCODE;
495 
496 END load_all_positions;
497 
498 END hri_opl_posh;