DBA Data[Home] [Help]

PACKAGE BODY: APPS.PER_OPL_ORGH

Source


1 PACKAGE BODY per_opl_orgh AS
2 /* $Header: perporgh.pkb 115.1 2004/06/17 03:25:22 vanantha noship $ */
3 
4 /******************************************************************************/
5 /*                                                                            */
6 /* OUTLINE / DEFINITIONS                                                      */
7 /*                                                                            */
8 /* A chain is defined for a organization as a list starting with the          */
9 /* organization which contains and successive higher level organizations      */
10 /* finishing with the highest level (top) organization.                       */
11 /*                                                                            */
12 /* IMPLEMENTATION LOGIC                                                       */
13 /*                                                                            */
14 /* The organization hierarchy table is populated by carrying out the          */
15 /* following steps:                                                           */
16 /*                                                                            */
17 /*  1) Empty out existing table                                               */
18 /*                                                                            */
19 /*  2) Loop through a view containing top organizations for each organization */
20 /*     hierarchy version                                                      */
21 /*                                                                            */
22 /*    i) Insert top organization chain into the organization hierarchy table  */
23 /*   ii) Insert chain for all organizations in that organization hierarchy    */
24 /*       version making use of the data structure to avoid recalculating the  */
25 /*       same 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_org_structure_elements.business_group_id%TYPE
44   ,organization_id      PER_org_structure_elements.organization_id_parent%TYPE
45   ,last_chng_date       DATE);
46 
47 /* Table type to hold information about the current chain */
48 TYPE g_chain_type IS TABLE OF g_link_record_type INDEX BY BINARY_INTEGER;
49 
50 /* Global structure holding information about the current chain */
51 g_crrnt_chain              g_chain_type;
52 
53 /* Simple table types */
54 TYPE g_date_tab_type IS TABLE OF DATE INDEX BY BINARY_INTEGER;
55 TYPE g_number_tab_type IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
56 TYPE g_varchar2_tab_type IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
57 
58 /* PLSQL table of tables representing category structure table */
59 g_cs_ost_id             g_number_tab_type;
60 g_cs_bgr_id             g_number_tab_type;
61 g_cs_osv_id             g_number_tab_type;
62 g_cs_sup_org_id         g_number_tab_type;
63 g_cs_sup_level          g_number_tab_type;
64 g_cs_sub_org_id         g_number_tab_type;
65 g_cs_sub_level          g_number_tab_type;
66 g_cs_sub_rlt_lvl        g_number_tab_type;
67 g_cs_last_chng          g_date_tab_type;
68 
69 /* Global tables for bulk fetch */
70 g_fetch_top_org_id      g_number_tab_type;
71 g_fetch_osv_id          g_number_tab_type;
72 g_fetch_ost_id          g_number_tab_type;
73 g_fetch_vno_id          g_number_tab_type;
74 g_fetch_prm_flg         g_varchar2_tab_type;
75 g_fetch_start_dt        g_date_tab_type;
76 g_fetch_end_dt          g_date_tab_type;
77 g_fetch_bgr_id          g_number_tab_type;
78 
79 g_cs_rows_to_insert    PLS_INTEGER;  -- Number of CS rows to insert
80 
81 /* Set to true to output to a concurrent log file */
82 g_conc_request_flag       BOOLEAN := FALSE;
83 
84 /* Number of rows bulk processed at a time */
85 g_chunk_size              PLS_INTEGER;
86 
87 /* Start / End of time dates */
88 g_start_of_time           DATE := hr_general.start_of_time;
89 g_end_of_time             DATE := hr_general.end_of_time;
90 
91 /******************************************************************************/
92 /* Inserts row into concurrent program log when the g_conc_request_flag has   */
93 /* been set to TRUE, otherwise does nothing                                   */
94 /******************************************************************************/
95 PROCEDURE output(p_text  VARCHAR2)
96   IS
97 
98 BEGIN
99 
100 /* Write to the concurrent request log if called from a concurrent request */
101   IF (g_conc_request_flag = TRUE) THEN
102 
103    /* Put text to log file */
104     fnd_file.put_line(FND_FILE.log, p_text);
105   END IF;
106 
107 END output;
108 
109 /******************************************************************************/
110 /* Recovers CS rows to insert when an exception occurs                        */
111 /******************************************************************************/
112 PROCEDURE recover_insert_cs_rows IS
113 
114 BEGIN
115   -- loop through rows still to insert one at a time
116   FOR i IN 1..g_cs_rows_to_insert LOOP
117 
118     -- Trap unique constraint errors
119     BEGIN
120 
121       INSERT INTO /*+ PARALLEL(<table name>, DEFAULT, DEFAULT) */ PER_org_hrchy_summary
122         (organization_structure_id
123         ,org_structure_version_id
124         ,org_business_group_id
125         ,organization_id
126         ,organization_level
127         ,sub_org_business_group_id
128         ,sub_organization_id
129         ,sub_organization_level
130         ,sub_org_relative_level
131         ,last_ptntl_change)
132           VALUES
133             (g_cs_ost_id(i)
134             ,g_cs_osv_id(i)
135             ,g_cs_bgr_id(i)
136             ,g_cs_sup_org_id(i)
137             ,g_cs_sup_level(i)
138             ,g_cs_bgr_id(i)
139             ,g_cs_sub_org_id(i)
140             ,g_cs_sub_level(i)
141             ,g_cs_sub_rlt_lvl(i)
142             ,g_cs_last_chng(i));
143 
144     EXCEPTION
145       WHEN OTHERS THEN
146 
147       /* Probable overlap on date tracked assignment rows */
148       output('Single insert error: ' || to_char(g_cs_sub_org_id(i)) ||
149              ' - ' || to_char(g_cs_sup_org_id(i)));
150       output('Inserting chain for: ' ||
151               to_char(g_cs_sub_org_id(i)) || ' in hierarchy version' ||
152               to_char(g_cs_osv_id(i)));
153       output(sqlerrm);
154       output(sqlcode);
155 
156     END;
157 
158   END LOOP;
159 
160   -- commit
161   commit;
162 
163 END recover_insert_cs_rows;
164 
165 
166 /******************************************************************************/
167 /* Bulk inserts rows from global temporary table to CS database table         */
168 /******************************************************************************/
169 PROCEDURE bulk_insert_cs_rows IS
170 
171 BEGIN
172   -- insert chunk of rows
173   FORALL i IN 1..g_cs_rows_to_insert
174     INSERT INTO /*+ PARALLEL(<table name>, DEFAULT, DEFAULT) */ PER_org_hrchy_summary
175         (organization_structure_id
176         ,org_structure_version_id
177         ,org_business_group_id
178         ,organization_id
179         ,organization_level
180         ,sub_org_business_group_id
181         ,sub_organization_id
182         ,sub_organization_level
183         ,sub_org_relative_level
184         ,last_ptntl_change)
185           VALUES
186             (g_cs_ost_id(i)
187             ,g_cs_osv_id(i)
188             ,g_cs_bgr_id(i)
189             ,g_cs_sup_org_id(i)
190             ,g_cs_sup_level(i)
191             ,g_cs_bgr_id(i)
192             ,g_cs_sub_org_id(i)
193             ,g_cs_sub_level(i)
194             ,g_cs_sub_rlt_lvl(i)
195             ,g_cs_last_chng(i));
196   -- commit the chunk of rows
197   COMMIT;
198 EXCEPTION
199   WHEN OTHERS THEN
200 
201 /* Unique constraint error */
202   rollback;
203   output('Warning - recovering (CS)');
204   recover_insert_cs_rows;
205 
206 END bulk_insert_cs_rows;
207 
208 /******************************************************************************/
209 /* Inserts row into global CS temporary table                                 */
210 /******************************************************************************/
211 PROCEDURE insert_cs_row( p_sup_organization_id     IN NUMBER
212                        , p_sup_level               IN NUMBER
213                        , p_sub_organization_id     IN NUMBER
214                        , p_sub_level               IN NUMBER
215                        , p_index                   IN NUMBER
216                        , p_last_ptntl_change       IN DATE ) IS
217 
218 BEGIN
219   -- increment the index
220   g_cs_rows_to_insert := g_cs_rows_to_insert + 1;
221   -- set the table structures
222   g_cs_sup_org_id(g_cs_rows_to_insert)   := p_sup_organization_id;
223   g_cs_sup_level(g_cs_rows_to_insert)    := p_sup_level;
224   g_cs_sub_org_id(g_cs_rows_to_insert)   := p_sub_organization_id;
225   g_cs_sub_level(g_cs_rows_to_insert)    := p_sub_level;
226   g_cs_sub_rlt_lvl(g_cs_rows_to_insert)  := p_sub_level - p_sup_level;
227   g_cs_ost_id(g_cs_rows_to_insert)       := g_fetch_ost_id(p_index);
228   g_cs_bgr_id(g_cs_rows_to_insert)       := g_fetch_bgr_id(p_index);
229   g_cs_osv_id(g_cs_rows_to_insert)       := g_fetch_osv_id(p_index);
230   g_cs_last_chng(g_cs_rows_to_insert)    := p_last_ptntl_change;
231 END insert_cs_row;
232 
233 
234 /******************************************************************************/
235 /* Updates all organizations in the organization hierarchy version starting   */
236 /* with the top organization.                                                 */
237 /******************************************************************************/
238 PROCEDURE calculate_chains( p_index        IN NUMBER ) IS
239 
240 /* Cursor picks out all organizations in the organization structure */
241 /* This cursor MUST return rows in the default order */
242   CURSOR organizations_csr IS
243   SELECT
244    hier.organization_id_child   organization_id
245   ,hier.last_update_date        last_update_date
246   ,LEVEL+1                      actual_level
247   FROM (SELECT
248          ose.organization_id_child
249         ,ose.organization_id_parent
250         ,NVL(ose.last_update_date, g_start_of_time)  last_update_date
251         FROM
252          PER_org_structure_elements   ose
253         WHERE ose.org_structure_version_id = g_fetch_osv_id(p_index))  hier
254   START WITH hier.organization_id_parent = g_fetch_top_org_id(p_index)
255   CONNECT BY PRIOR hier.organization_id_child = organization_id_parent;
256 /******************************/
257 /* DO NOT ADD ORDER BY CLAUSE */
258 /******************************/
259 
260   l_org_lvl          PLS_INTEGER;
261   l_last_org_lvl     PLS_INTEGER;
262 
263 BEGIN
264 
265 /* Store details for top organization */
266   g_crrnt_chain(1).organization_id   := g_fetch_top_org_id(p_index);
267   g_crrnt_chain(1).last_chng_date    := g_fetch_start_dt(p_index);
268 
269 /* Insert chain */
270   insert_cs_row
271     (p_sup_organization_id   => g_crrnt_chain(1).organization_id
272     ,p_sup_level             => 1
273     ,p_sub_organization_id   => g_crrnt_chain(1).organization_id
274     ,p_sub_level             => 1
275     ,p_index                 => p_index
276     ,p_last_ptntl_change     => g_crrnt_chain(1).last_chng_date);
277 
278 /* Loop through organizations in organization hierarchy version */
279   FOR org_rec IN organizations_csr LOOP
280 
281     l_org_lvl := org_rec.actual_level;
282 
283     IF (l_last_org_lvl > l_org_lvl) THEN
284     /* Reset end of chain */
285       FOR i IN l_org_lvl+1..l_last_org_lvl LOOP
286         g_crrnt_chain(i).organization_id := to_number(null);
287       END LOOP;
288     END IF;
289 
290     g_crrnt_chain(l_org_lvl).organization_id   := org_rec.organization_id;
291     g_crrnt_chain(l_org_lvl).last_chng_date    :=
292            GREATEST(org_rec.last_update_date,
293                     g_crrnt_chain(l_org_lvl - 1).last_chng_date);
294 
295     /* Loop through links in (stored) chain of organizations */
296       FOR l_sup_lvl IN 1..l_org_lvl LOOP
297 
298       /* Insert chain into CS */
299         insert_cs_row
300           (p_sup_organization_id   => g_crrnt_chain(l_sup_lvl).organization_id
301           ,p_sup_level             => l_sup_lvl
302           ,p_sub_organization_id   => g_crrnt_chain(l_org_lvl).organization_id
303           ,p_sub_level             => l_org_lvl
304           ,p_index                 => p_index
305           ,p_last_ptntl_change     => g_crrnt_chain(l_org_lvl).last_chng_date);
306 
307       END LOOP; -- Links in stored chain
308 
309   /* If the stored rows have reached a maximum, then insert them */
310     IF (g_cs_rows_to_insert > g_chunk_size) THEN
311       -- bulk insert rows processed so far
312       bulk_insert_cs_rows;
313       -- reset the index
314       g_cs_rows_to_insert := 0;
315     END IF;
316 
317     l_last_org_lvl := l_org_lvl;
318 
319   END LOOP;  -- organizations in hierarchy version
320 
321 EXCEPTION
322   WHEN OTHERS THEN
323 
324 /* ORA 01436 - loop in tree walk */
325   IF (SQLCODE = -1436) THEN
326     output('Loop found for organization id:  ' ||
327             to_char(g_fetch_top_org_id(p_index)));
328   ELSE
329 /* Some other error */
330     RAISE;
331   END IF;
332 
333 END calculate_chains;
334 
335 /******************************************************************************/
336 /* Loops through organization structure versions                              */
337 /******************************************************************************/
338 PROCEDURE collect_org_structures IS
339 
340 /* Pick out all organization structure versions and their top organizations */
341   CURSOR hrchy_version_csr IS
342   SELECT /*+ use_NL(ost,osv)*/DISTINCT      --Bug fix 3648736
343    ose.organization_id_parent
344   ,osv.org_structure_version_id
345   ,osv.organization_structure_id
346   ,osv.version_number
347   ,ost.primary_structure_flag
348   ,osv.date_from
349   ,NVL(osv.date_to,g_end_of_time)
350   ,osv.business_group_id
351   FROM
352    PER_org_structure_elements     ose
353   ,PER_org_structure_versions     osv
354   ,PER_organization_structures    ost
355   WHERE osv.org_structure_version_id = ose.org_structure_version_id
356   AND ost.organization_structure_id = osv.organization_structure_id
357   AND (ost.business_group_id=osv.business_group_id    --Bug fix 3648736
358 	         or ost.business_group_id is null
359 	         or osv.business_group_id is null)
360   AND (osv.business_group_id=ose.business_group_id
361 	       or osv.business_group_id is null
362             or ose.business_group_id is null)
363 --  AND ost.primary_structure_flag = 'Y'
364   AND NOT EXISTS
365     (SELECT NULL
366      FROM PER_org_structure_elements ose2
367      WHERE ose2.org_structure_version_id = ose.org_structure_version_id
368      AND ose2.organization_id_child = ose.organization_id_parent);
369 
370   l_return_code          PLS_INTEGER;
371   l_exit_main_loop       BOOLEAN := FALSE;
372   l_rows_fetched         PLS_INTEGER := g_chunk_size;
373 
374 BEGIN
375   -- initialise the g_cs_rows_to_insert
376   g_cs_rows_to_insert := 0;
377   -- initialise the current chain for CSF structure
378   FOR i IN 1..15 LOOP
379     g_crrnt_chain(i).organization_id := to_number(null);
380   END LOOP;
381   -- open main cursor
382   OPEN hrchy_version_csr;
383   <<main_loop>>
384   LOOP
385     -- bulk fetch rows limit the fetch to value of g_chunk_size
386     FETCH hrchy_version_csr
387     BULK COLLECT INTO
388           g_fetch_top_org_id,
389           g_fetch_osv_id,
390           g_fetch_ost_id,
391           g_fetch_vno_id,
392           g_fetch_prm_flg,
393           g_fetch_start_dt,
394           g_fetch_end_dt,
395           g_fetch_bgr_id
396     LIMIT g_chunk_size;
397     -- check to see if the last row has been fetched
398     IF hrchy_version_csr%NOTFOUND THEN
399       -- last row fetched, set exit loop flag
400       l_exit_main_loop := TRUE;
401       -- do we have any rows to process?
402       l_rows_fetched := MOD(hrchy_version_csr%ROWCOUNT,g_chunk_size);
403       -- note: if l_rows_fetched > 0 then more rows are required to be
404       -- processed and the l_rows_fetched will contain the exact number of
405       -- rows left to process
406       IF l_rows_fetched = 0 THEN
407         -- no more rows to process so exit loop
408         EXIT main_loop;
409       END IF;
410     END IF;
411 
412     -- Loop through organization hierarchy versions
413     FOR i IN 1..l_rows_fetched LOOP
414 
415       calculate_chains( p_index => i );
416 
417     END LOOP;
418     -- exit loop if required
419     IF l_exit_main_loop THEN
420       EXIT main_loop;
421     END IF;
422   END LOOP; -- main loop
423   CLOSE hrchy_version_csr;
424 /* Insert any remaining stored rows */
425   IF (g_cs_rows_to_insert > 0) THEN
426       bulk_insert_cs_rows;
427   END IF;
428 EXCEPTION
429   WHEN OTHERS THEN
430     -- unexpected error has occurred so close down
431     -- main bulk cursor if it is open
432     IF hrchy_version_csr%ISOPEN THEN
433       CLOSE hrchy_version_csr;
434     END IF;
435     -- re-raise error
436     RAISE;
437 END collect_org_structures;
438 
439 /******************************************************************************/
440 /* Main entry point to reload the organization hierarchy table                */
441 /******************************************************************************/
442 PROCEDURE load( p_chunk_size    IN NUMBER ) IS
443 
444   l_sql_stmt      VARCHAR2(2000);
445   l_dummy1        VARCHAR2(2000);
446   l_dummy2        VARCHAR2(2000);
447   l_schema        VARCHAR2(400);
448 
449 BEGIN
450 
451 /* Set chunk size */
452   g_chunk_size := p_chunk_size;
453 
454 /* Time at start */
455   output('PL/SQL Start:   ' || to_char(sysdate,'HH24:MI:SS'));
456 
457 /* Get PER schema name - get_app_info populates l_schema */
458   IF fnd_installation.get_app_info('PER',l_dummy1, l_dummy2, l_schema) THEN
459 
460   /* Empty out organization hierarchy tables */
461     l_sql_stmt := 'TRUNCATE TABLE ' || l_schema || '.PER_ORG_HRCHY_SUMMARY';
462     EXECUTE IMMEDIATE(l_sql_stmt);
463 
464   /* Write timing information to log */
465     output('Truncated organization Hierarchy tables:   '  ||
466            to_char(sysdate,'HH24:MI:SS'));
467 
468   /* Insert new organization hierarchy records */
469     collect_org_structures;
470 
471   /* Write timing information to log */
472     output('Re-populated organization Hierarchy table:  '  ||
473            to_char(sysdate,'HH24:MI:SS'));
474 
475   /* Gather index stats */
476 --    fnd_stats.gather_table_stats(l_schema, 'PER_CS_orgH');
477 
478   /* Write timing information to log */
479 --    output('Gathered stats:   '  ||
480 --           to_char(sysdate,'HH24:MI:SS'));
481 
482   END IF;
483 
484 END load;
485 
486 /******************************************************************************/
487 /* Entry point to be called from the concurrent manager                       */
488 /******************************************************************************/
489 PROCEDURE load_all_organizations( errbuf          OUT nocopy VARCHAR2,
490                                   retcode         OUT nocopy VARCHAR2,
491                                   p_chunk_size    IN NUMBER )
492 
493 IS
494 
495 BEGIN
496 
497 /* Enable output to concurrent request log */
498   g_conc_request_flag := TRUE;
499 
500 /* Call main function */
501   load(p_chunk_size => p_chunk_size);
502 
503 EXCEPTION
504   WHEN OTHERS THEN
505     errbuf := SQLERRM;
506     retcode := SQLCODE;
507 
508 END load_all_organizations;
509 
510 END PER_opl_orgh;