1 PACKAGE body FND_STATS AS
2 /* $Header: AFSTATSB.pls 120.12.12010000.10 2009/02/25 11:05:02 suchauha ship $ */
3 db_versn NUMBER :=81;
4 request_from VARCHAR2(7) DEFAULT 'U';
5 MAX_ERRORS_PRINTED NUMBER := 20 ; -- The max nof. allowable errors.
6 STD_GRANULARITY VARCHAR2(15) := 'DEFAULT' ; -- Global/partion
7 PART_GRANULARITY VARCHAR2(15) := 'PARTITION' ;-- Granularity is partition level.
8 ALL_GRANULARITY VARCHAR2(15) := 'ALL' ; -- Granularity is ALL.
9 INDEX_LEVEL NUMBER := 1 ; /* default ind_level for fudged ind. stats,
10 came to this value so that optimizer
11 prefers index access */
12 fnd_stattab VARCHAR2(30) := 'FND_STATTAB'; -- Name of the backup table
13 fnd_statown VARCHAR2(30) := 'APPLSYS'; -- Owner of the backup table
14 stat_tab_exist BOOLEAN := false;
15 dummy1 VARCHAR2(30);
16 dummy2 VARCHAR2(30);
17 dummybool BOOLEAN ;
18 cur_request_id NUMBER(15) DEFAULT NULL;
19 call_from_sqlplus BOOLEAN :=false;
20 fm_first_flag BOOLEAN :=true; -- Flush_monitoring first time call flag
21 stathist VARCHAR2(8);
22 def_degree NUMBER; -- default degree for parallel
23 g_Errors Error_Out;
24 -- New cursort to support MVs
25 CURSOR schema_cur IS
26 SELECT upper(oracle_username) sname
27 FROM fnd_oracle_userid
28 WHERE oracle_id BETWEEN 900 AND 999
29 AND read_only_flag = 'U'
30
31 UNION ALL
32
33 SELECT DISTINCT upper(oracle_username) sname
34 FROM fnd_oracle_userid a,
35 fnd_product_installations b
36 WHERE a.oracle_id = b.oracle_id
37 ORDER BY sname;
38
39 /************************************************************************/
40 /* Function : GET_BLOCKS */
41 /* Desciption: Gets the size in blocks of the given table. */
42 /************************************************************************/
43 FUNCTION GET_BLOCKS(schemaname IN VARCHAR2,
44 object_name IN VARCHAR2,
45 object_type IN VARCHAR2)
46 RETURN NUMBER
47 IS
48 total_blocks NUMBER;
49 total_bytes NUMBER;
50 unused_blocks NUMBER;
51 unused_bytes NUMBER;
52 last_extf NUMBER;
53 last_extb NUMBER;
54 last_usedblock NUMBER;
55 BEGIN
56 DBMS_SPACE.UNUSED_SPACE(upper(schemaname),upper(object_name),upper(object_type),total_blocks, total_bytes,unused_blocks,unused_bytes,last_extf,last_extb, last_usedblock);
57 RETURN total_blocks-unused_blocks;
58 EXCEPTION
59 WHEN OTHERS THEN
60 -- For partitioned tables, we will get an exception as it unused space
61 -- expects a partition spec. If table is partitioned, we definitely
62 -- do not want to do serial, so will return thold+1000.
63 RETURN fnd_stats.SMALL_TAB_FOR_PAR_THOLD+1000;
64 END;
65 /************************************************************************/
66 /* Procedure: SCHEMA_MONITORING */
67 /* Desciption: Non Public procedure that is called by */
68 /* ENABLE_SCHEMA_MONITORING or DISABLE_SCHEMA_MONITORING */
69 /************************************************************************/
70 PROCEDURE SCHEMA_MONITORING(mmode IN VARCHAR2,
71 schemaname IN VARCHAR2)
72 IS
73 TYPE name_tab
74 IS
75 TABLE OF dba_tables.table_name%TYPE;
76 tmp_str VARCHAR2(200);
77 names name_tab;
78 num_tables NUMBER := 0;
79 modeval VARCHAR2(5);
80 modbool VARCHAR2(6);
81 BEGIN
82 IF mmode ='ENABLE' THEN
83 modeval:='YES';
84 modbool:='TRUE';
85 ELSE
86 modeval:='NO';
87 modbool:='FALSE';
88 END IF;
89 IF (( db_versn > 80) AND
90 (
91 db_versn < 90
92 )
93 ) THEN
94 -- 8i does not have the ALTER_SCHEMA_TAB_MONITORING function,
95 -- therefore this has to be taken care of manually.
96 IF schemaname ='ALL' THEN -- call itself with the schema name
97 FOR c_schema IN schema_cur
98 LOOP
99 FND_STATS.SCHEMA_MONITORING(mmode,c_schema.sname);
100 END LOOP;
101 /* schema_cur */
102 ELSE -- schemaname<>'ALL'
103 SELECT table_name BULK COLLECT
104 INTO names
105 FROM dba_tables
106 WHERE owner = upper(schemaname)
107 AND
108 (
109 iot_type <> 'IOT_OVERFLOW'
110 OR iot_type IS NULL
111 )
112 AND TEMPORARY <> 'Y'
113 AND monitoring <> modeval; -- skip table that already have the selected mode
114 num_tables := SQL%ROWCOUNT;
115 FOR i IN 1..num_tables
116 LOOP
117 IF mmode ='ENABLE' THEN
118 tmp_str:='ALTER TABLE '
119 ||upper(schemaname)
120 ||'.'
121 ||names(i)
122 ||' MONITORING';
123 elsif mmode ='DISABLE' THEN
124 tmp_str:='ALTER TABLE '
125 ||upper(schemaname)
126 ||'.'
127 ||names(i)
128 ||' NOMONITORING';
129 END IF;
130 EXECUTE IMMEDIATE tmp_str;
131 dbms_output.put_line(tmp_str);
132 END LOOP;
133 END IF; -- if schemaname ='ALL'
134 elsif ((db_versn > 90 ) AND
135 (
136 db_versn < 100
137 )
138 ) THEN
139 -- 8i does not have the ALTER_SCHEMA_TAB_MONITORING function,
140 -- therefore 9i specific function calls have to be dynamic sql.
141 IF schemaname ='ALL' THEN
142 tmp_str:='BEGIN dbms_stats.ALTER_DATABASE_TAB_MONITORING(monitoring=>'
143 ||modbool
144 ||',sysobjs=>FALSE); END;';
145 EXECUTE IMMEDIATE tmp_str;
146 ELSE
147 tmp_str:='BEGIN dbms_stats.ALTER_SCHEMA_TAB_MONITORING(ownname=>:SCHEMANAME,monitoring=>'
148 ||modbool
149 ||'); END;';
150 EXECUTE IMMEDIATE tmp_str USING schemaname;
151 END IF;
152 ELSE -- db version is 10, do nothing as it is taken care of by default.
153 -- db_versn is a 2 char code, which is 10 for 10g.
154 NULL;
155 END IF;
156 END;
157 /************************************************************************/
158 /* Procedure: ENABLE_SCHEMA_MONITORING */
159 /* Desciption: Enables MONITORING option for all tables in the */
160 /* given schema. If schemaname is not specified, defaults to 'ALL'. */
161 /************************************************************************/
162 PROCEDURE ENABLE_SCHEMA_MONITORING(schemaname IN VARCHAR2)
163 IS
164 BEGIN
165 SCHEMA_MONITORING('ENABLE',schemaname);
166 END;
167 /************************************************************************/
168 /* Procedure: ENABLE_SCHEMA_MONITORING */
169 /* Desciption: Enables MONITORING option for all tables in the */
170 /* given schema. If schemaname is not specified, defaults to 'ALL'. */
171 /************************************************************************/
172 PROCEDURE DISABLE_SCHEMA_MONITORING(schemaname IN VARCHAR2)
173 IS
174 BEGIN
175 SCHEMA_MONITORING('DISABLE',schemaname);
176 END;
177 /************************************************************************/
178 /* Procedure: GET_PARALLEL */
179 /* Desciption: Gets the min between number of parallel max servers */
180 /* and the cpu_count. This number is used as a default degree of */
181 /* parallelism is none is specified. */
182 /************************************************************************/
183 PROCEDURE GET_PARALLEL(parallel IN OUT NOCOPY NUMBER)
184 IS
185 BEGIN
186 SELECT MIN(to_number(value))
187 INTO parallel
188 FROM v$parameter
189 WHERE name ='parallel_max_servers'
190 OR name ='cpu_count';
191
192 END;
193 /************************************************************************/
194 /* Function: GET_REQUEST_ID */
195 /* Desciption: Gets the current request_id */
196 /* If the call is thru a concurrent program, the conc request id is */
197 /* returned, which can be later over-ridden if restart case. */
198 /* If is is not thru a concurrent program, a user request id is */
199 /* generated. */
200 /************************************************************************/
201 FUNCTION GET_REQUEST_ID RETURN NUMBER
202 IS
203 str_request_id VARCHAR2(30);
204 request_id_l NUMBER(15);
205 l_message VARCHAR2(1000);
206 BEGIN
207 -- FND_PROFILE.GET('CONC_REQUEST_ID', str_request_id);
208 -- if str_request_id is not null then -- call is via a conc program
209 IF FND_GLOBAL.CONC_REQUEST_ID > 0 THEN -- call is via a conc program
210 request_from :='C'; -- set request type C for CONC
211 request_id_l := FND_GLOBAL.CONC_REQUEST_ID; -- set request id to conc request id
212 elsif ( FND_GLOBAL.USER_ID > 0) THEN -- check if call from apps program
213 request_from :='P'; -- P for PROG , cal by program
214 -- generate it from sequence
215 SELECT fnd_stats_hist_s.nextval
216 INTO request_id_l
217 FROM dual;
218
219 ELSE -- call not from within apps context, maybe sqlplus
220 request_from:='U'; -- U for USER, called from sqlplus etc
221 -- generate it from sequence
222 SELECT fnd_stats_hist_s.nextval
223 INTO request_id_l
224 FROM dual;
225
226 END IF;
227 -- dbms_output.put_line('Request_id is '||request_id);
228 -- dbms_output.put_line('Effective Request_id is '||request_id_l);
229 -- l_message := 'Request_id is '||cur_request_id|| 'Effective Request_id is '||request_id_l;
230 -- FND_FILE.put_line(FND_FILE.log,l_message);
231 RETURN request_id_l;
232 END;
233 /************************************************************************/
234 /* Procedure: CREATE_STAT_TABLE */
235 /* Desciption: Create stats table to hold statistics. Default parameters*/
236 /* are used for tablename and owner. */
237 /************************************************************************/
238 PROCEDURE CREATE_STAT_TABLE
239 IS
240 PRAGMA AUTONOMOUS_TRANSACTION;
241 BEGIN
242 -- if stat_tab has already been created, do not recreate
243 BEGIN
244 dummy1:='N';
245 EXECUTE immediate 'select ''Y'' from all_tables '
246 || ' where owner='''
247 ||fnd_statown
248 || ''' and table_name='''
249 ||fnd_stattab
250 ||'''' INTO dummy1;
251 EXCEPTION
252 WHEN OTHERS THEN
253 stat_tab_exist:=false;
254 END;
255 IF dummy1 ='Y' THEN
256 stat_tab_exist := true;
257 END IF;
258 IF stat_tab_exist = false THEN
259 DBMS_STATS.CREATE_STAT_TABLE(fnd_statown,fnd_stattab);
260 stat_tab_exist := true;
261 END IF;
262 EXCEPTION
263 WHEN OTHERS THEN
264 raise;
265 END ;
266 /* CREATE_STAT_TABLE */
267 /************************************************************************/
268 /* Procedure: CREATE_STAT_TABLE */
269 /* Desciption: Create stats table to hold statistics. Caller can specify*/
270 /* cusotm values for schema, tablename or tablespace name */
271 /************************************************************************/
272 PROCEDURE CREATE_STAT_TABLE( schemaname IN VARCHAR2,
273 tabname IN VARCHAR2,
274 tblspcname IN VARCHAR2 DEFAULT NULL)
275 IS
276 PRAGMA AUTONOMOUS_TRANSACTION;
277 BEGIN
278 DBMS_STATS.CREATE_STAT_TABLE(schemaname,tabname,tblspcname);
279 EXCEPTION
280 WHEN OTHERS THEN
281 raise;
282 END;
283 /* CREATE_STAT_TABLE(,,) */
284 /**
285 * procedure TRANSFER_STATS : Wrapper around backup/restore stats procedures,
286 * required for the new "Backup/Restore Statistics"
287 * conc program.
288 */
289 PROCEDURE TRANSFER_STATS( errbuf OUT NOCOPY VARCHAR2,
290 retcode OUT NOCOPY VARCHAR2,
291 action IN VARCHAR2,
292 schemaname IN VARCHAR2,
293 tabname IN VARCHAR2,
294 stattab IN VARCHAR2 DEFAULT 'FND_STATTAB',
295 statid IN VARCHAR2 )
296 IS
297 exist_insufficient EXCEPTION;
298 pragma exception_init(exist_insufficient,-20000);
299 l_message VARCHAR2(1000);
300 BEGIN
301 BEGIN
302 create_stat_table(schemaname,stattab);
303 EXCEPTION
304 WHEN OTHERS THEN
305 NULL;
306 END;
307 IF(upper(action) = 'BACKUP') THEN
308 IF(tabname IS NULL) THEN
309 BACKUP_SCHEMA_STATS( schemaname , statid );
310 ELSE
311 BACKUP_TABLE_STATS( schemaname , tabname , statid ) ;
312 END IF;
313 elsif(upper(action) = 'RESTORE') THEN
314 IF(tabname IS NULL) THEN
318 END IF;
315 RESTORE_SCHEMA_STATS( schemaname , statid );
316 ELSE
317 RESTORE_TABLE_STATS(schemaname , tabname , statid );
319 END IF;
320 EXCEPTION
321 WHEN exist_insufficient THEN
322 errbuf := sqlerrm ;
323 retcode := '2';
324 l_message := errbuf;
325 FND_FILE.put_line(FND_FILE.log,l_message);
326 raise;
327 WHEN OTHERS THEN
328 errbuf := sqlerrm ;
329 retcode := '2';
330 l_message := errbuf;
331 FND_FILE.put_line(FND_FILE.log,l_message);
332 raise;
333 END;
334 /************************************************************************/
335 /* Procedure: BACKUP_SCHEMA_STATS */
336 /* Desciption: Copies schema statistics to fnd_stattab table. If schema */
337 /* name is 'ALL', copies all schema stats. Statistics stored with */
338 /* a particular stat id. */
339 /************************************************************************/
340 PROCEDURE BACKUP_SCHEMA_STATS( schemaname IN VARCHAR2,
341 statid IN VARCHAR2)
342 IS
343 exist_insufficient EXCEPTION;
344 pragma exception_init(exist_insufficient,-20002);
345 BEGIN
346 -- First create the FND_STATTAB if it doesn't exist.
347 BEGIN
348 FND_STATS.CREATE_STAT_TABLE();
349 EXCEPTION
350 WHEN exist_insufficient THEN
351 NULL;
352 END;
353 IF (upper(schemaname) <> 'ALL') THEN
354 DBMS_STATS.EXPORT_SCHEMA_STATS(schemaname, fnd_stattab, statid, fnd_statown);
355 ELSE
356 FOR c_schema IN schema_cur
357 LOOP
358 DBMS_STATS.EXPORT_SCHEMA_STATS(c_schema.sname, fnd_stattab, statid, fnd_statown);
359 END LOOP;
360 /* schema_cur */
361 END IF;
362 END;
363 /* BACKUP_SCHEMA_STATS() */
364 /************************************************************************/
365 /* Procedure: BACKUP_TABLE_STATS */
366 /* Desciption: Copies table statistics along with index and column */
367 /* stats if cascade is true. Procedure is called from concurrent program*/
368 /* manager. */
369 /************************************************************************/
370 PROCEDURE BACKUP_TABLE_STATS( errbuf OUT NOCOPY VARCHAR2,
371 retcode OUT NOCOPY VARCHAR2,
372 schemaname IN VARCHAR2,
373 tabname IN VARCHAR2,
374 statid IN VARCHAR2 DEFAULT 'BACKUP',
375 partname IN VARCHAR2 DEFAULT NULL,
376 CASCADE IN BOOLEAN DEFAULT true )
377 IS
378 exist_insufficient EXCEPTION;
379 pragma exception_init(exist_insufficient,-20000);
380 l_message VARCHAR2(1000);
381 BEGIN
382 FND_STATS.BACKUP_TABLE_STATS(schemaname, tabname, statid, partname, CASCADE);
383 EXCEPTION
384 WHEN exist_insufficient THEN
385 errbuf := sqlerrm ;
386 retcode := '2';
387 l_message := errbuf;
388 FND_FILE.put_line(FND_FILE.log,l_message);
389 raise;
390 WHEN OTHERS THEN
391 errbuf := sqlerrm ;
392 retcode := '2';
393 l_message := errbuf;
394 FND_FILE.put_line(FND_FILE.log,l_message);
395 raise;
396 END;
397 /* BACKUP_TABLE_STATS */
398 /************************************************************************/
399 /* Procedure: BACKUP_TABLE_STATS */
400 /* Desciption: Copies table statistics along with index and column */
401 /* stats if cascade is true. Procedure is called by the concurrent */
402 /* program manager version of BACKUP_TABLE_STATS. Procedure can also be */
403 /* called from sqlplus */
404 /************************************************************************/
405 PROCEDURE BACKUP_TABLE_STATS( schemaname IN VARCHAR2,
406 tabname IN VARCHAR2,
407 statid IN VARCHAR2 DEFAULT 'BACKUP',
408 partname IN VARCHAR2 DEFAULT NULL,
409 CASCADE IN BOOLEAN DEFAULT true )
410 IS
411 exist_insufficient EXCEPTION;
412 pragma exception_init(exist_insufficient,-20002);
413 BEGIN
414 -- First create the FND_STATTAB if it doesn't exist.
415 BEGIN
416 FND_STATS.CREATE_STAT_TABLE();
417 EXCEPTION
418 WHEN exist_insufficient THEN
419 NULL;
420 END;
421 DBMS_STATS.EXPORT_TABLE_STATS(schemaname, tabname, partname, fnd_stattab, statid, CASCADE, fnd_statown) ;
422 END;
423 /* BACKUP_TABLE_STATS() */
424 /************************************************************************/
425 /* Procedure: RESTORE_SCHEMA_STATS */
426 /* Desciption: Retores schema statistics from fnd_stattab table. If */
427 /* schema name is 'ALL', copies all schema stats. Statistics restored */
428 /* with a particular stat id. */
432 IS
429 /************************************************************************/
430 PROCEDURE RESTORE_SCHEMA_STATS(schemaname IN VARCHAR2,
431 statid IN VARCHAR2 DEFAULT NULL)
433 BEGIN
434 IF (upper(schemaname) <> 'ALL') THEN
435 DBMS_STATS.IMPORT_SCHEMA_STATS(schemaname, fnd_stattab, statid, fnd_statown);
436 ELSE
437 FOR c_schema IN schema_cur
438 LOOP
439 DBMS_STATS.IMPORT_SCHEMA_STATS(c_schema.sname, fnd_stattab, statid, fnd_statown);
440 END LOOP;
441 /* schema_cur */
442 END IF;
443 END;
444 /* RESTORE_SCHEMA_STATS() */
445 /************************************************************************/
446 /* Procedure: RESTORE_TABLE_STATS */
447 /* Desciption: Retores table statistics from fnd_stattab table. If */
448 /* cascase is true, restores column as well as index stats too. This */
449 /* procedure is called from concurrent program manager. */
450 /************************************************************************/
451 PROCEDURE RESTORE_TABLE_STATS(errbuf OUT NOCOPY VARCHAR2,
452 retcode OUT NOCOPY VARCHAR2,
453 ownname IN VARCHAR2,
454 tabname IN VARCHAR2,
455 statid IN VARCHAR2 DEFAULT NULL,
456 partname IN VARCHAR2 DEFAULT NULL,
457 CASCADE IN BOOLEAN DEFAULT true )
458 IS
459 exist_insufficient EXCEPTION;
460 exist_invalid EXCEPTION;
461 pragma exception_init(exist_insufficient,-20000);
462 pragma exception_init(exist_invalid,-20001);
463 l_message VARCHAR2(1000);
464 BEGIN
465 FND_STATS.RESTORE_TABLE_STATS(ownname,tabname,statid,partname,CASCADE);
466 EXCEPTION
467 WHEN exist_insufficient THEN
468 errbuf := sqlerrm;
469 retcode := '2';
470 l_message := errbuf;
471 FND_FILE.put_line(FND_FILE.log,l_message);
472 raise;
473 WHEN exist_invalid THEN
474 errbuf := 'ORA-20001: Invalid or inconsistent values in the user stattab ='
475 ||fnd_stattab
476 ||' statid='
477 ||statid ;
478 retcode := '2';
479 l_message := errbuf;
480 FND_FILE.put_line(FND_FILE.log,l_message);
481 raise;
482 WHEN OTHERS THEN
483 errbuf := sqlerrm ;
484 retcode := '2';
485 l_message := errbuf;
486 FND_FILE.put_line(FND_FILE.log,l_message);
487 raise;
488 END;
489 /* RESTORE_TABLE_STATS */
490 /************************************************************************/
491 /* Procedure: RESTORE_TABLE_STATS */
492 /* Desciption: Retores table statistics from fnd_stattab table. If */
493 /* cascase is true, restores column as well as index stats too. This */
494 /* procedure is called from the concurrent program manager version of */
495 /* RESTORE_TABLE_STATS as well as from sqlplus */
496 /************************************************************************/
497 PROCEDURE RESTORE_TABLE_STATS(ownname IN VARCHAR2,
498 tabname IN VARCHAR2,
499 statid IN VARCHAR2 DEFAULT NULL,
500 partname IN VARCHAR2 DEFAULT NULL,
501 CASCADE IN BOOLEAN DEFAULT true )
502 IS
503 BEGIN
504 DBMS_STATS.IMPORT_TABLE_STATS(ownname,tabname,partname, fnd_stattab,statid,CASCADE,fnd_statown);
505 END;
506 /* RESTORE_TABLE_STATS */
507 /************************************************************************/
508 /* Procedure: RESTORE_INDEX_STATS */
509 /* Desciption: Retores index statistics from fnd_stattab table for a */
510 /* particular table. */
511 /************************************************************************/
512 PROCEDURE RESTORE_INDEX_STATS(ownname IN VARCHAR2,
513 indname IN VARCHAR2,
514 statid IN VARCHAR2 DEFAULT NULL,
515 partname IN VARCHAR2 DEFAULT NULL)
516 IS
517 BEGIN
518 DBMS_STATS.IMPORT_INDEX_STATS(ownname,indname,partname,fnd_stattab, statid,fnd_statown) ;
519 END;
520 /* RESTORE_INDEX_STATS */
521 /************************************************************************/
522 /* Procedure: RESTORE_COLUMN_STATS */
523 /* Desciption: Retores column statistics from fnd_stattab table for a */
524 /* particular column. */
525 /************************************************************************/
526 PROCEDURE RESTORE_COLUMN_STATS(ownname IN VARCHAR2,
527 tabname IN VARCHAR2,
528 colname IN VARCHAR2,
529 partname IN VARCHAR2 DEFAULT NULL,
530 statid IN VARCHAR2 DEFAULT NULL)
531 IS
532 BEGIN
533 DBMS_STATS.IMPORT_COLUMN_STATS(ownname, tabname, colname, partname, fnd_stattab, statid, fnd_statown) ;
534 END;
535 /* RESTORE_COLUMN_STATS() */
539 /* columns seeded in the fnd_histogram_cols table. */
536 /************************************************************************/
537 /* Procedure: RESTORE_COLUMN_STATS */
538 /* Desciption: Retores column statistics from fnd_stattab table for all */
540 /************************************************************************/
541 PROCEDURE RESTORE_COLUMN_STATS(statid IN VARCHAR2 DEFAULT NULL)
542 IS
543 /* cursor col_cursor is
544 select upper(b.oracle_username) ownname ,
545 a.table_name tabname,
546 a.column_name colname,
547 a.partition partname
548 from FND_HISTOGRAM_COLS a,
549 FND_ORACLE_USERID b,
550 FND_PRODUCT_INSTALLATIONS c
551 where a.application_id = c.application_id
552 and c.oracle_id = b.oracle_id
553 order by ownname, tabname, column_name;
554 */
555 -- New cursor to support MVs
556 CURSOR col_cursor IS
557 SELECT NVL(upper(b.oracle_username), a.owner) ownname ,
558 a.table_name tabname ,
559 a.column_name colname ,
560 a.partition partname
561 FROM FND_HISTOGRAM_COLS a,
562 FND_ORACLE_USERID b ,
563 FND_PRODUCT_INSTALLATIONS c
564 WHERE a.application_id = c.application_id (+)
565 AND c.oracle_id = b.oracle_id (+)
566 ORDER BY ownname,
567 tabname,
568 colname;
569
570 BEGIN
571 FOR c_rec IN col_cursor
572 LOOP
573 DBMS_STATS.IMPORT_COLUMN_STATS(c_rec.ownname,c_rec.tabname, c_rec.colname,c_rec.partname, fnd_stattab,statid,fnd_statown);
574 END LOOP;
575 END;
576 /* RESTORE_COLUMN_STATS */
577 /************************************************************************/
578 /* Procedure: DLOG */
579 /* Desciption: Writes out log messages to the conc program log. */
580 /************************************************************************/
581 PROCEDURE dlog(p_str IN VARCHAR2)
582 IS
583 BEGIN
584 dbms_output.put_line(SUBSTR(p_str,1,250));
585 FND_FILE.put_line(FND_FILE.log,p_str);
586 END dlog;
587 /************************************************************************/
588 /* Procedure: GATHER_TABLE_STATS_PVT */
589 /* Desciption: Private package that now calls dbms_stats dynamically */
590 /* depending upon the version of the database. For 8i, */
591 /* dbms_stats is called as before, for higher versions, it */
592 /* is called with the no_invalidate flag. */
593 /************************************************************************/
594 PROCEDURE GATHER_TABLE_STATS_PVT(ownname IN VARCHAR2,
595 tabname IN VARCHAR2,
596 estimate_percent IN NUMBER DEFAULT NULL,
597 degree IN NUMBER DEFAULT NULL,
598 method_opt VARCHAR2 DEFAULT 'FOR ALL COLUMNS SIZE 1',
599 partname IN VARCHAR2 DEFAULT NULL,
600 CASCADE IN BOOLEAN DEFAULT true,
601 granularity IN VARCHAR2 DEFAULT 'DEFAULT',
602 stattab VARCHAR2 DEFAULT NULL,
603 statown VARCHAR2 DEFAULT NULL,
604 invalidate IN VARCHAR2 DEFAULT 'Y' )
605 IS
606 l_tmp_str VARCHAR2(600);
607 no_invalidate VARCHAR2(1);
608 BEGIN
609 IF ((upper(invalidate) ='Y') OR
610 (
611 upper(invalidate) ='YES'
612 )
613 ) THEN
614 no_invalidate:='N';
615 ELSE
616 no_invalidate:='Y';
617 END IF;
618 -- If db version is < 9iR2, OR it is 92 and no_inv is false OR it is > 92
619 -- and no_inv is true, calls dbms_stats statically, else ...
620 IF ( (db_versn <= 92) OR
621 (
622 db_versn=92 AND no_invalidate='N'
623 )
624 OR
625 (
626 db_versn>=100 AND no_invalidate='Y'
627 )
628 ) THEN
629 DBMS_STATS.GATHER_TABLE_STATS( ownname => ownname ,
630 tabname => tabname , estimate_percent => estimate_percent , degree => degree ,
631 method_opt => method_opt , block_sample => FALSE , partname => partname ,
632 CASCADE => CASCADE , granularity => granularity , stattab => stattab , statown => statown );
633 ELSE
634 l_tmp_str:= 'BEGIN DBMS_STATS.GATHER_TABLE_STATS( ownname => :ownname ,'
635 || ' tabname => :tabname ,'
636 || ' estimate_percent => :estimate_percent ,'
637 || ' degree => :degree ,'
638 || ' method_opt => :method_opt ,'
639 || ' block_sample => FALSE ,'
640 || ' partname => :partname ,'
641 || ' granularity => :granularity ,'
642 || ' stattab => :stattab ,'
646 || ' no_invalidate => TRUE ,';
643 || ' statown => :statown, ';
644 IF (no_invalidate ='Y') THEN
645 l_tmp_str:=l_tmp_str
647 ELSE
648 l_tmp_str:=l_tmp_str
649 || ' no_invalidate => FALSE ,';
650 END IF;
651 IF (CASCADE) THEN
652 l_tmp_str:=l_tmp_str
653 || ' cascade => TRUE ';
654 ELSE
655 l_tmp_str:=l_tmp_str
656 || ' cascade => FALSE ';
657 END IF;
658 l_tmp_str:=l_tmp_str
659 || ' ); end;';
660 EXECUTE IMMEDIATE l_tmp_str USING ownname , tabname , estimate_percent , degree , method_opt , partname , granularity , stattab , statown;
661 END IF;
662 EXCEPTION
663 WHEN OTHERS THEN
664 raise;
665 END;
666 /* GATHER_TABLE_STATS_PVT */
667 /************************************************************************/
668 /* Procedure: GATHER_INDEX_STATS_PVT */
669 /* Desciption: Private package that now calls dbms_stats dynamically */
670 /* depending upon the version of the database. For 8i, */
671 /* dbms_stats is called as before, for higher versions, it */
672 /* is called with the invalidate flag. */
673 /************************************************************************/
674 PROCEDURE GATHER_INDEX_STATS_PVT(ownname IN VARCHAR2,
675 indname IN VARCHAR2,
676 estimate_percent IN NUMBER DEFAULT NULL,
677 degree IN NUMBER DEFAULT NULL,
678 partname IN VARCHAR2 DEFAULT NULL,
679 invalidate IN VARCHAR2 DEFAULT 'Y' )
680 IS
681 l_tmp_str VARCHAR2(600);
682 no_invalidate VARCHAR2(1);
683 BEGIN
684 IF ((upper(invalidate) ='Y') OR
685 (
686 upper(invalidate) ='YES'
687 )
688 ) THEN
689 no_invalidate:='N';
690 ELSE
691 no_invalidate:='Y';
692 END IF;
693 -- If db version is < 9iR2, calls dbms_stats statically, else ...
694 IF (db_versn <= 92) THEN
695 DBMS_STATS.GATHER_INDEX_STATS( ownname => ownname , indname => indname , estimate_percent => estimate_percent , partname => partname );
696 ELSE
697 l_tmp_str:= 'BEGIN DBMS_STATS.GATHER_INDEX_STATS( ownname => :ownname ,'
698 || ' indname => :indname ,'
699 || ' estimate_percent => :estimate_percent ,'
700 || ' degree => :degree ,'
701 || ' partname => :partname ,';
702 IF (no_invalidate ='Y') THEN
703 l_tmp_str:=l_tmp_str
704 || ' no_invalidate => TRUE ';
705 ELSE
706 l_tmp_str:=l_tmp_str
707 || ' no_invalidate => FALSE ';
708 END IF;
709 l_tmp_str:=l_tmp_str
710 ||' ); END;';
711 EXECUTE IMMEDIATE l_tmp_str USING ownname , indname , estimate_percent , degree , partname ;
712 END IF;
713 END;
714 /* GATHER_INDEX_STATS_PVT */
715 /************************************************************************/
716 /* Procedure: GATHER_SCHEMA_STATS */
717 /* Desciption: Gather schema statistics. This is the concurrent program */
718 /* manager version. */
719 /************************************************************************/
720 PROCEDURE GATHER_SCHEMA_STATS(errbuf OUT NOCOPY VARCHAR2,
721 retcode OUT NOCOPY VARCHAR2,
722 schemaname IN VARCHAR2,
723 estimate_percent IN NUMBER,
724 degree IN NUMBER ,
725 internal_flag IN VARCHAR2,
726 request_id IN NUMBER,
727 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
728 OPTIONS IN VARCHAR2 DEFAULT 'GATHER',
729 modpercent IN NUMBER DEFAULT 10,
730 invalidate IN VARCHAR2 DEFAULT 'Y' )
731 IS
732 exist_insufficient EXCEPTION;
733 bad_input EXCEPTION;
734 pragma exception_init(exist_insufficient,-20000);
735 pragma exception_init(bad_input,-20001);
736 l_message VARCHAR2(1000);
737 Error_counter NUMBER := 0;
738 --Errors Error_Out; -- commented for bug error handling
739 -- num_request_id number(15);
740 conc_request_id NUMBER(15);
741 degree_parallel NUMBER(4);
742 BEGIN
743 -- Set the package body variable.
744 stathist := hmode;
745 -- check first if degree is null
746 IF degree IS NULL THEN
747 degree_parallel:=def_degree;
748 ELSE
752 || schemaname
749 degree_parallel := degree;
750 END IF;
751 l_message := 'In GATHER_SCHEMA_STATS , schema_name= '
753 || ' percent= '
754 || TO_CHAR(estimate_percent)
755 || ' degree = '
756 || TO_CHAR(degree_parallel)
757 || ' internal_flag= '
758 || internal_flag ;
759 FND_FILE.put_line(FND_FILE.log,l_message);
760 BEGIN
761 FND_STATS.GATHER_SCHEMA_STATS(schemaname, estimate_percent, degree_parallel, internal_flag , request_id,stathist, OPTIONS,modpercent,invalidate); -- removed errors parameter for error handling
762 EXCEPTION
763 WHEN exist_insufficient THEN
764 errbuf := sqlerrm ;
765 retcode := '2';
766 l_message := errbuf;
767 FND_FILE.put_line(FND_FILE.log,l_message);
768 raise;
769 WHEN bad_input THEN
770 errbuf := sqlerrm ;
771 retcode := '2';
772 l_message := errbuf;
773 FND_FILE.put_line(FND_FILE.log,l_message);
774 raise;
775 WHEN OTHERS THEN
776 errbuf := sqlerrm ;
777 retcode := '2';
778 l_message := errbuf;
779 FND_FILE.put_line(FND_FILE.log,l_message);
780 raise;
781 END;
782 FOR i IN 0..MAX_ERRORS_PRINTED
783 LOOP
784 EXIT
785 WHEN g_Errors(i) IS NULL;
786 Error_counter:=i+1;
787 FND_FILE.put_line(FND_FILE.log,'Error #'
788 ||Error_counter
789 || ': '
790 ||g_Errors(i));
791 -- added to send back status to concurrent program manager bug 2625022
792 errbuf := sqlerrm ;
793 retcode := '2';
794 END LOOP;
795 END;
796 /* GATHER_SCHEMA_STATS */
797 /************************************************************************/
798 /* Procedure: GATHER_SCHEMA_STATISTICS */
799 /* Desciption: Gather schema statistics. This is the sqlplus version. It*/
800 /* does not have any o/p parameters */
801 /************************************************************************/
802 PROCEDURE GATHER_SCHEMA_STATISTICS(schemaname IN VARCHAR2,
803 estimate_percent IN NUMBER ,
804 degree IN NUMBER ,
805 internal_flag IN VARCHAR2,
806 request_id IN NUMBER,
807 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
808 OPTIONS IN VARCHAR2 DEFAULT 'GATHER',
809 modpercent IN NUMBER DEFAULT 10,
810 invalidate IN VARCHAR2 DEFAULT 'Y' )
811 IS
812 Errors Error_Out;
813 BEGIN
814 call_from_sqlplus:=true;
815 FND_STATS.GATHER_SCHEMA_STATS_SQLPLUS(schemaname, estimate_percent, degree,internal_flag, Errors, request_id,hmode,OPTIONS ,modpercent,invalidate);
816 END;
817 /* end of GATHER_SCHEMA_STATISTICS */
818 /************************************************************************/
819 /* Procedure: GATHER_SCHEMA_STATS_SQLPLUS */
820 /* Desciption: Gather schema statistics. This is called by concurrent */
821 /* manager version of GATHER_SCHEMA_STATS. */
822 /* Notes: internal_flag='INTERNAL' will call dbms_utility.analyze_schema*/
823 /* insead of dbms_stats.gather_schema_stats */
824 /* internal_flag='NOBACKUP' will bypass dbms_stats.export_schema_stats */
825 /************************************************************************/
826 PROCEDURE GATHER_SCHEMA_STATS_SQLPLUS(schemaname IN VARCHAR2,
827 estimate_percent IN NUMBER ,
828 degree IN NUMBER ,
829 internal_flag IN VARCHAR2 ,
830 Errors OUT NOCOPY Error_Out,
831 request_id IN NUMBER DEFAULT NULL,
832 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
833 OPTIONS IN VARCHAR2 DEFAULT 'GATHER',
834 modpercent IN NUMBER DEFAULT 10,
835 invalidate IN VARCHAR2 DEFAULT 'Y' )
836 IS
837 TYPE name_tab
838 IS
839 TABLE OF dba_tables.table_name%TYPE;
840 TYPE partition_tab
841 IS
842 TABLE OF sys.dba_tab_modifications.partition_name%TYPE;
843 TYPE partition_type_tab
844 IS
845 TABLE OF dba_tables.partitioned%TYPE;
846 part_flag partition_type_tab;
847 names name_tab;
848 pnames partition_tab;
849 num_tables NUMBER := 0;
850 l_message VARCHAR2(1000) ;
851 granularity VARCHAR2(12);
852 exist_insufficient EXCEPTION;
853 pragma exception_init(exist_insufficient,-20002);
854 err_cnt BINARY_INTEGER := 0;
855 degree_parallel NUMBER(4);
856 str_request_id VARCHAR(30);
860 SELECT type ,
857 -- Cursor to get list of tables and indexes with no stats
858 CURSOR empty_cur(schemaname VARCHAR2)
859 IS
861 owner,
862 name
863 FROM
864 ( SELECT 'TABLE' type,
865 owner ,
866 table_name name
867 FROM dba_tables
868 WHERE owner=upper(schemaname)
869 AND
870 (
871 iot_type <> 'IOT_OVERFLOW'
872 OR iot_type IS NULL
873 )
874 AND TEMPORARY <> 'Y'
875 AND last_analyzed IS NULL
876
877 UNION ALL
878
879 SELECT 'INDEX' type,
880 owner ,
881 index_name name
882 FROM dba_indexes
883 WHERE
884 (
885 table_owner=upper(schemaname)
886 OR owner =upper(schemaname)
887 )
888 AND index_type <> 'LOB'
889 AND index_type <>'DOMAIN'
890 AND TEMPORARY <> 'Y'
891 AND last_analyzed IS NULL
892 )
893 ORDER BY type ,
894 owner,
895 name ;
896
897 CURSOR nomon_tab(schemaname VARCHAR2)
898 IS
899 SELECT owner,
900 table_name
901 FROM dba_tables dt
902 WHERE owner=upper(schemaname)
903 AND
904 (
905 iot_type <> 'IOT_OVERFLOW'
906 OR iot_type IS NULL
907 )
908 AND TEMPORARY <> 'Y'
909 AND monitoring ='NO'
910 AND NOT EXISTS
911 (SELECT NULL
912 FROM dba_external_tables de
913 WHERE de.table_name=dt.table_name
914 AND de.owner =dt.owner
915 )-- added this to avoid externale tables being selected
916 AND NOT EXISTS
917 ( SELECT NULL
918 FROM dba_tab_statistics dts
919 WHERE dts.stattype_locked IS NOT NULL
920 AND dts.table_name=dt.table_name
921 AND dts.owner =dt.owner
922 ); -- added by saleem to avoid locked objects
923 CURSOR lock_stats_tab(schemaname VARCHAR2)
924 IS -- cursor added by saleem to display the warning message for tables with locked stats
925 SELECT table_name
926 FROM dba_tab_statistics
927 WHERE stattype_locked IS NOT NULL
928 AND owner=upper(schemaname); -- added to display the warning for locked stats
929 BEGIN
930 -- Set the package body variable.
931 stathist := hmode;
932 -- if request id (restart case) is provided, then this is the cur_request_id
933 -- valid for both conc program and sql plus case.
934 IF request_id IS NOT NULL THEN
935 cur_request_id := request_id;
936 END IF;
937 -- get degree of parallelism
938 IF degree IS NULL THEN
939 degree_parallel:=def_degree;
940 ELSE
941 degree_parallel := degree;
942 END IF;
943 -- Initialize the TABLE Errors
944 Errors(0) := NULL;
945 granularity := FND_STATS.ALL_GRANULARITY; -- granularity will be ALL for all tables
946 err_cnt := 0;
947 -- If a specific schema is given
948 IF (upper(schemaname) <> 'SYS') THEN
949 IF (upper(schemaname) <> 'ALL') THEN
950 -- Insert/update the fnd_stats_hist table
951 IF(upper(stathist)<> 'NONE') THEN
952 BEGIN
953 -- if(cur_request_id is null) then
954 -- cur_request_id := GET_REQUEST_ID(request_id);
955 -- end if;
956 FND_STATS.UPDATE_HIST(schemaname=>schemaname, objectname=>schemaname, objecttype=>'SCHEMA', partname=>NULL, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'S', percent=>NVL(estimate_percent,10));
957 END;
958 END IF; --if(upper(stathist)<> 'NONE')
959 -- backup the existing schema stats
960 IF ( (upper(internal_flag) = 'BACKUP') ) THEN
961 FND_STATS.BACKUP_SCHEMA_STATS( schemaname );
962 END IF;
963 IF(upper(OPTIONS)='GATHER') THEN
964 SELECT table_name ,
968 FROM dba_tables dt
965 partitioned BULK COLLECT
966 INTO names,
967 part_flag
969 WHERE owner = upper(schemaname)
970 AND
971 (
972 iot_type <> 'IOT_OVERFLOW'
973 OR iot_type IS NULL
974 )
975 AND TEMPORARY <> 'Y' -- Bypass if temporary tables for bug#1108002
976 AND NOT EXISTS
977 (SELECT NULL
978 FROM fnd_stats_hist fsh
979 WHERE dt.owner =fsh.schema_name
980 AND fsh.REQUEST_ID = cur_request_id
981 AND fsh.object_type ='CASCADE'
982 AND fsh.history_mode=stathist
983 AND dt.table_name = fsh.object_name
984 AND LAST_GATHER_END_TIME IS NOT NULL
985 )
986 AND NOT EXISTS
987 (SELECT NULL
988 FROM fnd_exclude_table_stats fets,
989 fnd_oracle_userid fou ,
990 fnd_product_installations fpi
991 WHERE fou.oracle_username=upper(schemaname)
992 AND fou.oracle_id =fpi.oracle_id
993 AND fpi.application_id = fets.application_id
994 AND dt.table_name = fets.table_name
995 ) -- added by saleem for bug 7479909
996 AND NOT EXISTS
997 ( SELECT NULL
998 FROM dba_tab_statistics dts
999 WHERE dts.stattype_locked IS NOT NULL
1000 AND dts.table_name=dt.table_name
1001 AND dts.owner =dt.owner
1002 )
1003 ORDER BY table_name;
1004
1005 num_tables := SQL%ROWCOUNT;
1006 FOR i IN 1..num_tables
1007 LOOP
1008 IF ( part_flag(i) = 'YES' ) THEN
1009 granularity := FND_STATS.ALL_GRANULARITY ;
1010 ELSE
1011 granularity := FND_STATS.STD_GRANULARITY;
1012 END IF;
1013 BEGIN
1014 FND_STATS.GATHER_TABLE_STATS(ownname => schemaname,
1015 tabname => names(i), percent => NVL(estimate_percent,10),
1016 degree => degree_parallel, partname=>NULL, CASCADE => TRUE,
1017 granularity => granularity, hmode => stathist,
1018 invalidate=> invalidate );
1019 EXCEPTION
1020 WHEN OTHERS THEN
1021 Errors(err_cnt) := 'ERROR: While GATHER_TABLE_STATS:
1022 object_name='
1023 ||schemaname
1024 ||'.'
1025 ||names(i)
1026 ||'***'
1027 ||SQLERRM
1028 ||'***' ;
1029 Errors(err_cnt+1) := NULL;
1030 err_cnt := err_cnt+1;
1031 END;
1032 END LOOP;
1033 /* end of individual tables */
1034 FOR rec_cur IN lock_stats_tab(upper(schemaname)) -- added by saleem to display warning for tables with locked stats
1035 LOOP
1036 dbms_output.put_line('stats on table '
1037 || rec_cur.table_name
1038 || 'is locked ');
1039 dlog('stats on table '
1040 || rec_cur.table_name
1041 || ' is locked ');
1042 --fnd_file.put_line(FND_FILE.log,s_message);
1043 END LOOP;
1044 elsif ( (upper(OPTIONS)='GATHER AUTO') OR
1045 (
1046 upper(OPTIONS)='LIST AUTO'
1047 )
1048 ) THEN
1049 -- if db_versn > 81 then call flush, else use whatever
1050 -- data is available in dtm
1051 IF db_versn > 81 THEN
1052 IF(fm_first_flag) THEN
1053 EXECUTE IMMEDIATE 'BEGIN DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO; END;' ;
1054 fm_first_flag := false;
1055 END IF;
1056 END IF;
1057 -- gather stats for stale tables/partitions. Potentially, there
1058 -- could be some redundent stats gathering, if for eg the table
1059 -- and one of its partitions, both are statle. gather_table_stats
1060 -- would get called twice, once for the table ( which would gather
1061 -- stats for the partitions too, and the partition by itself. The
1062 -- probability of this happening is small, and even if that happens
1063 -- on a rare occasion, the overhead should not be that high, so
1064 -- leaving it as it is for the moment. This can be revisited if
1065 -- tests and experience show that that is not the case.
1066 SELECT iv.table_name,
1067 iv.partition_name -- ,subpartition_name
1068 BULK COLLECT
1069 INTO names,
1070 pnames -- ,spnames
1071 FROM
1072 ( SELECT dtm.table_name,
1073 dtm.partition_name
1074 FROM sys.dba_tab_modifications dtm
1075 WHERE dtm.table_owner = upper(schemaname)
1076 AND dtm.partition_name IS NULL
1077 AND EXISTS
1078 ( SELECT NULL
1079 FROM dba_tables dt
1080 WHERE dt.owner =dtm.table_owner
1081 AND dt.table_name=dtm.table_name
1082 AND
1083 (
1084 NVL(dtm.inserts,0)+NVL(dtm.updates,0)+NVL(dtm.deletes,0)
1085 )
1086 > (modpercent*NVL(dt.num_rows,0))/100
1087 )
1088
1089 UNION ALL
1090
1091 SELECT dtm.table_name,
1092 dtm.partition_name
1093 FROM sys.dba_tab_modifications dtm
1094 WHERE dtm.table_owner = upper(schemaname)
1095 AND dtm.partition_name IS NOT NULL
1096 AND EXISTS
1100 AND dtp.table_name =dtm.table_name
1097 ( SELECT NULL
1098 FROM dba_tab_partitions dtp
1099 WHERE dtp.table_owner =dtm.table_owner
1101 AND dtp.partition_name=dtm.partition_name
1102 AND
1103 (
1104 NVL(dtm.inserts,0)+NVL(dtm.updates,0)+NVL(dtm.deletes,0)
1105 )
1106 > (modpercent*NVL(dtp.num_rows,0))/100
1107 )
1108 ) iv
1109 ORDER BY table_name;
1110
1111 num_tables := SQL%ROWCOUNT;
1112 FOR i IN 1..num_tables
1113 LOOP
1114 BEGIN
1115 IF (upper(OPTIONS)='GATHER AUTO') THEN
1116 FND_STATS.GATHER_TABLE_STATS(ownname => schemaname,
1117 tabname => names(i), percent => NVL(estimate_percent,10),
1118 degree => degree_parallel, partname=>pnames(i),
1119 CASCADE => TRUE, granularity => granularity,
1120 hmode => stathist, invalidate=> invalidate );
1121 ELSE
1122 dlog('Statistics on '
1123 ||schemaname
1124 ||'.'
1125 ||names(i)
1126 ||'Partition '
1127 ||NVL(pnames(i),'n/a')
1128 ||' are Stale');
1129 END IF;
1130 EXCEPTION
1131 WHEN OTHERS THEN
1132 Errors(err_cnt) := 'ERROR: While GATHER_TABLE_STATS:
1133 object_name='
1134 ||schemaname
1135 ||'.'
1136 ||names(i)
1137 ||'***'
1138 ||SQLERRM
1139 ||'***' ;
1140 Errors(err_cnt+1) := NULL;
1141 err_cnt := err_cnt+1;
1142 END;
1143 END LOOP;
1144 /* end of individual tables */
1145 FOR rec_cur IN lock_stats_tab(upper(schemaname)) -- added by saleem to display warning for tables with locked stats
1146 LOOP
1147 dbms_output.put_line('stats on table '
1148 || rec_cur.table_name
1149 || 'is locked ');
1150 dlog('stats on table '
1151 || rec_cur.table_name
1152 || ' is locked ');
1153 --fnd_file.put_line(FND_FILE.log,s_message);
1154 END LOOP;
1155 -- GATHER AUTO includes GATHER EMPTY, so gather stats
1156 -- on any unalalyzed tables and/or indexes.
1157 FOR c_rec IN empty_cur(upper(schemaname))
1158 LOOP
1159 IF c_rec.type = 'TABLE' THEN
1160 IF (upper(OPTIONS)='GATHER AUTO') THEN
1161 FND_STATS.GATHER_TABLE_STATS(ownname => c_rec.owner, tabname => c_rec.name,
1162 percent => NVL(estimate_percent,10),
1163 degree => degree_parallel, partname=>NULL, CASCADE => TRUE, granularity => granularity,
1164 hmode => stathist, invalidate=> invalidate );
1165 ELSE
1166 dlog('Table '
1167 ||c_rec.owner
1168 ||'.'
1169 ||c_rec.name
1170 ||' is missing statistics.');
1171 END IF;
1172 elsif c_rec.type ='INDEX' THEN
1173 IF (upper(OPTIONS)='GATHER AUTO') THEN
1174 fnd_stats.gather_index_stats(ownname=>c_rec.owner, indname=>c_rec.name, percent=>NVL(estimate_percent,10), invalidate=>invalidate);
1175 ELSE
1176 dlog('Index '
1177 ||c_rec.owner
1181 END IF;
1178 ||'.'
1179 ||c_rec.name
1180 ||' is missing statistics! ');
1182 END IF;
1183 END LOOP;
1184 -- Check if there are any tables in the schema which does not have
1185 -- monitoring enabled. If yes, gather stats for them using 10% and
1186 -- enable monitoring for such tables so that we have data for them
1187 -- in dba_tab_modifications for next time.
1188 FOR c_rec IN nomon_tab(upper(schemaname))
1189 LOOP
1190 IF (upper(OPTIONS)='GATHER AUTO') THEN
1191 FND_STATS.GATHER_TABLE_STATS(ownname => c_rec.owner,
1192 tabname => c_rec.table_name, percent => NVL(estimate_percent,10), degree => degree_parallel,
1193 partname=>NULL, CASCADE => TRUE, granularity => granularity, hmode => stathist, invalidate=> invalidate );
1194 EXECUTE IMMEDIATE 'alter table '
1195 ||c_rec.owner
1196 ||'.'
1197 ||c_rec.table_name
1198 ||' monitoring';
1199 dlog('Monitoring has now been enabled for Table '
1200 ||c_rec.owner
1201 ||'.'
1202 ||c_rec.table_name
1203 ||'. Stats were gathered.' );
1204 ELSE
1205 dlog('Monitoring is not enabled for Table '
1206 ||c_rec.owner
1207 ||'.'
1208 ||c_rec.table_name );
1209 END IF;
1210 END LOOP; -- nomon_tab
1211 elsif ( (upper(OPTIONS)='GATHER EMPTY') OR
1212 (
1213 upper(OPTIONS)='LIST EMPTY'
1214 )
1215 ) THEN
1216 FOR c_rec IN empty_cur(upper(schemaname))
1217 LOOP
1218 IF c_rec.type = 'TABLE' THEN
1219 IF (upper(OPTIONS)='GATHER EMPTY') THEN
1220 FND_STATS.GATHER_TABLE_STATS(ownname => c_rec.owner, tabname => c_rec.name,
1221 percent => NVL(estimate_percent,10), degree => degree_parallel, partname=>NULL, CASCADE => TRUE,
1222 granularity => granularity, hmode => stathist, invalidate=> invalidate );
1223 ELSE
1224 dlog('Table '
1225 ||c_rec.owner
1226 ||'.'
1227 ||c_rec.name
1228 ||' is missing statistics! ');
1229 END IF;
1230 elsif c_rec.type ='INDEX' THEN
1231 IF (upper(OPTIONS)='GATHER EMPTY') THEN
1232 fnd_stats.gather_index_stats(ownname=>c_rec.owner, indname=>c_rec.name, percent=>NVL(estimate_percent,10), invalidate=>invalidate);
1233 ELSE
1234 dlog('Statistics for Index '
1235 ||c_rec.owner
1236 ||'.'
1237 ||c_rec.name
1238 ||' are Empty');
1239 END IF;
1240 END IF;
1241 END LOOP;
1242 FOR rec_cur IN lock_stats_tab(upper(schemaname)) -- added by saleem to display warning for tables with locked stats
1243 LOOP
1244 dbms_output.put_line('stats on table '
1245 || rec_cur.table_name
1246 || ' is locked ');
1247 dlog('stats on table '
1248 || rec_cur.table_name
1249 || ' is locked ');
1250 --fnd_file.put_line(FND_FILE.log,s_message);
1251 END LOOP;
1252 END IF;
1253 /* end of if upper(options)= */
1254 -- End timestamp
1255 IF(upper(stathist) <> 'NONE') THEN
1259 END IF;
1256 BEGIN
1257 FND_STATS.UPDATE_HIST(schemaname=>schemaname, objectname=>schemaname, objecttype=>'SCHEMA', partname=>NULL, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'E' );
1258 END;
1260 ELSE
1261 /* This is for ALL schema */
1262 FOR c_schema IN schema_cur
1263 LOOP
1264 --dbms_output.put_line('start of schema = '|| c_schema.sname);
1265 -- make a recursive call to gather_schema_stats
1266 GATHER_SCHEMA_STATS_SQLPLUS(schemaname=>c_schema.sname , estimate_percent=>estimate_percent ,
1267 degree=>degree , internal_flag=>internal_flag , Errors=> Errors , request_id=>request_id , hmode=>stathist ,
1268 OPTIONS=>OPTIONS , modpercent=>modpercent , invalidate=> invalidate );
1269 /* for rec_cur in lock_stats_tab -- added by saleem
1270 loop
1271 dbms_output.put_line('stats on table ' || rec_cur.table_name || 'is locked ');
1272 dlog('stats on table ' || rec_cur.table_name || 'is locked ');
1273 s_message := 'stats on table ' || rec_cur.table_name || ' is locked ' ;
1274 fnd_file.put_line(FND_FILE.log,s_message);
1275 end loop; */
1276 END LOOP;
1277 /* schema_cur */
1278 END IF;
1279 ELSE -- schema is SYS, print message in log.
1280 dlog('Gathering statistics on the SYS schema using FND_STATS is not allowed.');
1281 dlog('Please use DBMS_STATS package to gather stats on SYS objects.');
1282 END IF; -- end of schema<> SYS
1283 END;
1284 /* GATHER_SCHEMA_STATS_SQLPLUS */
1285 /************************************************************************/
1286 /* Procedure: GATHER_SCHEMA_STATS */
1287 /* Desciption: Gather schema statistics. This is called by concurrent */
1288 /* manager version of GATHER_SCHEMA_STATS. */
1289 /* Notes: internal_flag='INTERNAL' will call dbms_utility.analyze_schema*/
1290 /* insead of dbms_stats.gather_schema_stats */
1291 /* internal_flag='NOBACKUP' will bypass dbms_stats.export_schema_stats */
1292 /************************************************************************/
1293 PROCEDURE GATHER_SCHEMA_STATS(schemaname IN VARCHAR2,
1294 estimate_percent IN NUMBER ,
1295 degree IN NUMBER ,
1296 internal_flag IN VARCHAR2 ,
1297 --Errors OUT NOCOPY Error_Out,-- commented for handling errors
1298 request_id IN NUMBER DEFAULT NULL,
1299 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
1300 OPTIONS IN VARCHAR2 DEFAULT 'GATHER',
1301 modpercent IN NUMBER DEFAULT 10,
1302 invalidate IN VARCHAR2 DEFAULT 'Y' )
1303 IS
1304 TYPE name_tab
1305 IS
1306 TABLE OF dba_tables.table_name%TYPE;
1307 TYPE partition_tab
1308 IS
1309 TABLE OF sys.dba_tab_modifications.partition_name%TYPE;
1310 TYPE partition_type_tab
1311 IS
1312 TABLE OF dba_tables.partitioned%TYPE;
1313 part_flag partition_type_tab;
1314 names name_tab;
1315 pnames partition_tab;
1316 num_tables NUMBER := 0;
1317 l_message VARCHAR2(1000) ;
1318 granularity VARCHAR2(12);
1319 exist_insufficient EXCEPTION;
1320 pragma exception_init(exist_insufficient,-20002);
1321 err_cnt BINARY_INTEGER := 0;
1322 degree_parallel NUMBER(4);
1323 str_request_id VARCHAR(30);
1324 -- Cursor to get list of tables and indexes with no stats
1325 CURSOR empty_cur(schemaname VARCHAR2)
1326 IS
1327 SELECT type ,
1328 owner,
1329 name
1330 FROM
1331 ( SELECT 'TABLE' type,
1332 owner ,
1333 table_name name
1334 FROM dba_tables dt
1335 WHERE owner=upper(schemaname)
1336 AND
1337 (
1338 iot_type <> 'IOT_OVERFLOW'
1339 OR iot_type IS NULL
1340 )
1341 AND TEMPORARY <> 'Y'
1342 AND last_analyzed IS NULL
1343 -- leave alone if excluded table
1344 AND NOT EXISTS
1345 (SELECT NULL
1346 FROM fnd_exclude_table_stats fets,
1347 fnd_oracle_userid fou ,
1348 fnd_product_installations fpi
1349 WHERE fou.oracle_username=upper(schemaname)
1350 AND fou.oracle_id =fpi.oracle_id
1351 AND fpi.application_id = fets.application_id
1355 UNION
1352 AND dt.table_name = fets.table_name
1353 )
1354
1356
1357 SELECT DISTINCT 'TABLE' type ,
1358 table_owner owner,
1359 table_name name
1360 FROM dba_indexes di
1361 WHERE
1362 (
1363 di.table_owner=upper(schemaname)
1364 OR di.owner =upper(schemaname)
1365 )
1366 AND di.index_type <> 'LOB'
1367 AND di.temporary <> 'Y'
1368 AND di.last_analyzed IS NULL
1369 AND NOT EXISTS
1370 (SELECT NULL
1371 FROM fnd_exclude_table_stats fets,
1372 fnd_oracle_userid fou ,
1373 fnd_product_installations fpi
1374 WHERE fou.oracle_username=upper(schemaname)
1375 AND fou.oracle_id =fpi.oracle_id
1376 AND fpi.application_id =fets.application_id
1377 AND di.table_name =fets.table_name
1378 )
1379 )
1380 ORDER BY type ,
1381 owner,
1382 name ;
1383
1384 CURSOR nomon_tab(schemaname VARCHAR2)
1385 IS
1386 SELECT owner,
1387 table_name
1388 FROM dba_tables dt
1389 WHERE owner=upper(schemaname)
1390 AND
1391 (
1392 iot_type <> 'IOT_OVERFLOW'
1393 OR iot_type IS NULL
1394 )
1395 AND TEMPORARY <> 'Y'
1396 AND monitoring ='NO'
1397 AND NOT EXISTS
1398 (SELECT NULL
1399 FROM dba_external_tables de
1400 WHERE de.table_name=dt.table_name
1401 AND de.owner =dt.owner
1402 )-- added this to avoid externale tables being selected
1403 AND NOT EXISTS
1404 ( SELECT NULL
1405 FROM dba_tab_statistics dts
1406 WHERE dts.stattype_locked IS NOT NULL
1407 AND dts.table_name=dt.table_name
1408 AND dts.owner =dt.owner
1409 ); -- added this to avoid locked objects
1410 CURSOR lock_stats_tab(schemaname VARCHAR2)
1411 IS -- cursor added by saleem to display the warning message for tables with locked stats
1412 SELECT table_name
1413 FROM dba_tab_statistics
1414 WHERE stattype_locked IS NOT NULL
1415 AND owner=upper(schemaname); -- added to display the warning for locked stats
1416 BEGIN
1417 -- Set the package body variable.
1418 stathist := hmode;
1419 -- if request id (restart case) is provided, then this is the cur_request_id
1420 -- valid for both conc program and sql plus case.
1421 IF request_id IS NOT NULL THEN
1422 cur_request_id := request_id;
1423 END IF;
1424 -- get degree of parallelism
1425 IF degree IS NULL THEN
1426 degree_parallel:=def_degree;
1427 ELSE
1428 degree_parallel := degree;
1429 END IF;
1430 -- Initialize the TABLE Errors
1431 --Errors(0) := NULL; -- commented the initialization so that the errors will not be cleared
1432 granularity := FND_STATS.ALL_GRANULARITY; -- granularity will be ALL for all tables
1433 err_cnt := 0;
1434 -- If a specific schema is given
1435 IF (upper(schemaname) <> 'SYS') THEN
1436 IF (upper(schemaname) <> 'ALL') THEN
1437 -- Insert/update the fnd_stats_hist table
1438 IF(upper(stathist)<> 'NONE') THEN
1439 BEGIN
1440 -- if(cur_request_id is null) then
1441 -- cur_request_id := GET_REQUEST_ID(request_id);
1442 -- end if;
1443 FND_STATS.UPDATE_HIST(schemaname=>schemaname, objectname=>schemaname,
1444 objecttype=>'SCHEMA', partname=>NULL, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'S',
1445 percent=>NVL(estimate_percent,10));
1446 END;
1447 END IF; --if(upper(stathist)<> 'NONE')
1451 END IF;
1448 -- backup the existing schema stats
1449 IF ( (upper(internal_flag) = 'BACKUP') ) THEN
1450 FND_STATS.BACKUP_SCHEMA_STATS( schemaname );
1452 IF(upper(OPTIONS)='GATHER') THEN
1453 SELECT table_name ,
1454 partitioned BULK COLLECT
1455 INTO names,
1456 part_flag
1457 FROM dba_tables dt
1458 WHERE owner = upper(schemaname)
1459 AND
1460 (
1461 iot_type <> 'IOT_OVERFLOW'
1462 OR iot_type IS NULL
1463 )
1464 AND TEMPORARY <> 'Y' -- Bypass if temporary tables for bug#1108002
1465 AND NOT EXISTS
1466 (SELECT NULL
1467 FROM fnd_stats_hist fsh
1468 WHERE dt.owner =fsh.schema_name
1469 AND fsh.REQUEST_ID = cur_request_id
1470 AND fsh.object_type ='CASCADE'
1471 AND fsh.history_mode=stathist
1472 AND dt.table_name = fsh.object_name
1473 AND LAST_GATHER_END_TIME IS NOT NULL
1474 )
1475 -- leave alone if excluded table
1476 AND NOT EXISTS
1477 (SELECT NULL
1478 FROM fnd_exclude_table_stats fets,
1479 fnd_oracle_userid fou ,
1480 fnd_product_installations fpi
1481 WHERE fou.oracle_username=upper(schemaname)
1482 AND fou.oracle_id =fpi.oracle_id
1483 AND fpi.application_id = fets.application_id
1484 AND dt.table_name = fets.table_name
1485 )
1486 AND NOT EXISTS
1487 ( SELECT NULL
1488 FROM dba_tab_statistics dts
1489 WHERE dts.stattype_locked IS NOT NULL
1490 AND dts.table_name=dt.table_name
1491 AND dts.owner =dt.owner
1492 )
1493 ORDER BY table_name;
1494
1495 num_tables := SQL%ROWCOUNT;
1496 FOR i IN 1..num_tables
1497 LOOP
1498 IF ( part_flag(i) = 'YES' ) THEN
1499 granularity := FND_STATS.ALL_GRANULARITY ;
1500 ELSE
1501 granularity := FND_STATS.STD_GRANULARITY;
1502 END IF;
1503 BEGIN
1504 FND_STATS.GATHER_TABLE_STATS(ownname => schemaname, tabname => names(i),
1505 percent => NVL(estimate_percent,10), degree => degree_parallel, partname=>NULL, CASCADE => TRUE,
1506 granularity => granularity, hmode => stathist, invalidate=> invalidate );
1507 EXCEPTION
1508 WHEN OTHERS THEN
1509 g_Errors(err_cnt) := 'ERROR: While GATHER_TABLE_STATS:
1510 object_name='
1511 ||schemaname
1512 ||'.'
1513 ||names(i)
1514 ||'***'
1515 ||SQLERRM
1516 ||'***' ;
1517 g_Errors(err_cnt+1) := NULL;
1518 err_cnt := err_cnt+1;
1519 END;
1520 END LOOP;
1521 /* end of individual tables */
1522 FOR rec_cur IN lock_stats_tab(upper(schemaname)) -- added by saleem to display warning for tables with locked stats
1526 || 'is locked ');
1523 LOOP
1524 dbms_output.put_line('stats on table '
1525 || rec_cur.table_name
1527 dlog('stats on table '
1528 || rec_cur.table_name
1529 || ' is locked ');
1530 -- s_message := 'stats on table ' || rec_cur.table_name || ' is locked ' ;
1531 --fnd_file.put_line(FND_FILE.log,s_message);
1532 END LOOP;
1533 elsif ( (upper(OPTIONS)='GATHER AUTO') OR
1534 (
1535 upper(OPTIONS)='LIST AUTO'
1536 )
1537 ) THEN
1538 -- if db_versn > 81 then call flush, else use whatever
1539 -- data is available in dtm
1540 IF db_versn > 81 THEN
1541 IF(fm_first_flag) THEN
1542 EXECUTE IMMEDIATE 'BEGIN DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO; END;' ;
1543 fm_first_flag := false;
1544 END IF;
1545 END IF;
1546 -- gather stats for stale tables/partitions. Potentially, there
1547 -- could be some redundent stats gathering, if for eg the table
1548 -- and one of its partitions, both are statle. gather_table_stats
1549 -- would get called twice, once for the table ( which would gather
1550 -- stats for the partitions too, and the partition by itself. The
1551 -- probability of this happening is small, and even if that happens
1552 -- on a rare occasion, the overhead should not be that high, so
1553 -- leaving it as it is for the moment. This can be revisited if
1554 -- tests and experience show that that is not the case.
1555 SELECT iv.table_name,
1556 iv.partition_name -- ,subpartition_name
1557 BULK COLLECT
1558 INTO names,
1559 pnames -- ,spnames
1560 FROM
1561 ( SELECT dtm.table_name,
1562 dtm.partition_name
1563 FROM sys.dba_tab_modifications dtm
1564 WHERE dtm.table_owner = upper(schemaname)
1565 AND dtm.partition_name IS NULL
1566 AND EXISTS
1567 ( SELECT NULL
1568 FROM dba_tables dt
1569 WHERE dt.owner =dtm.table_owner
1570 AND dt.table_name =dtm.table_name
1571 AND dt.partitioned='NO'
1572 AND
1573 (
1574 NVL(dtm.inserts,0)+NVL(dtm.updates,0)+NVL(dtm.deletes,0)
1575 )
1576 > (modpercent*NVL(dt.num_rows,0))/100
1577 )
1578
1579 UNION ALL
1580
1581 SELECT dtm.table_name,
1582 dtm.partition_name
1583 FROM sys.dba_tab_modifications dtm
1584 WHERE dtm.table_owner = upper(schemaname)
1585 AND dtm.partition_name IS NOT NULL
1586 AND EXISTS
1587 ( SELECT NULL
1588 FROM dba_tab_partitions dtp
1589 WHERE dtp.table_owner =dtm.table_owner
1590 AND dtp.table_name =dtm.table_name
1591 AND dtp.partition_name=dtm.partition_name
1592 AND
1593 (
1597 )
1594 NVL(dtm.inserts,0)+NVL(dtm.updates,0)+NVL(dtm.deletes,0)
1595 )
1596 > (modpercent*NVL(dtp.num_rows,0))/100
1598 ) iv
1599 ORDER BY table_name;
1600
1601 num_tables := SQL%ROWCOUNT;
1602 FOR i IN 1..num_tables
1603 LOOP
1604 BEGIN
1605 IF (upper(OPTIONS)='GATHER AUTO') THEN
1606 FND_STATS.GATHER_TABLE_STATS(ownname => schemaname,
1607 tabname => names(i), percent => NVL(estimate_percent,10), degree => degree_parallel, partname=>pnames(i),
1608 CASCADE => TRUE, granularity => granularity, hmode => stathist, invalidate=> invalidate );
1609 ELSE
1610 dlog('Statistics on '
1611 ||schemaname
1612 ||'.'
1613 ||names(i)
1614 ||'Partition '
1615 ||NVL(pnames(i),'n/a')
1616 ||' are Stale');
1617 END IF;
1618 EXCEPTION
1619 WHEN OTHERS THEN
1620 g_Errors(err_cnt) := 'ERROR: While GATHER_TABLE_STATS:
1621 object_name='
1622 ||schemaname
1623 ||'.'
1624 ||names(i)
1625 ||'***'
1626 ||SQLERRM
1627 ||'***' ;
1628 g_Errors(err_cnt+1) := NULL;
1629 err_cnt := err_cnt+1;
1630 END;
1631 END LOOP;
1632 /* end of individual tables */
1633 FOR rec_cur IN lock_stats_tab(upper(schemaname)) -- added by saleem to display warning for tables with locked stats
1634 LOOP
1635 dbms_output.put_line('stats on table '
1636 || rec_cur.table_name
1637 || ' is locked ');
1638 dlog('stats on table '
1639 || rec_cur.table_name
1640 || ' is locked ');
1641 -- s_message := 'stats on table ' || rec_cur.table_name || ' is locked ' ;
1642 --fnd_file.put_line(FND_FILE.log,s_message);
1643 END LOOP;
1644 -- GATHER AUTO includes GATHER EMPTY, so gather stats
1645 -- on any unalalyzed tables and/or indexes.
1646 FOR c_rec IN empty_cur(upper(schemaname))
1647 LOOP
1648 IF c_rec.type = 'TABLE' THEN
1649 IF (upper(OPTIONS)='GATHER AUTO') THEN
1650 FND_STATS.GATHER_TABLE_STATS(ownname => c_rec.owner,
1651 tabname => c_rec.name, percent => NVL(estimate_percent,10), degree => degree_parallel, partname=>NULL,
1652 CASCADE => TRUE, granularity => granularity, hmode => stathist, invalidate=> invalidate );
1653 ELSE
1654 dlog('Table '
1655 ||c_rec.owner
1656 ||'.'
1657 ||c_rec.name
1658 ||' is missing statistics.');
1659 END IF;
1660 END IF;
1661 END LOOP;
1662 -- Check if there are any tables in the schema which does not have
1663 -- monitoring enabled. If yes, gather stats for them using 10% and
1664 -- enable monitoring for such tables so that we have data for them
1665 -- in dba_tab_modifications for next time.
1666 FOR c_rec IN nomon_tab(upper(schemaname))
1667 LOOP
1671 granularity => granularity, hmode => stathist, invalidate=> invalidate );
1668 IF (upper(OPTIONS)='GATHER AUTO') THEN
1669 FND_STATS.GATHER_TABLE_STATS(ownname => c_rec.owner, tabname => c_rec.table_name,
1670 percent => NVL(estimate_percent,10), degree => degree_parallel, partname=>NULL, CASCADE => TRUE,
1672 EXECUTE IMMEDIATE 'alter table '
1673 ||c_rec.owner
1674 ||'.'
1675 ||c_rec.table_name
1676 ||' monitoring';
1677 dlog('Monitoring has now been enabled for Table '
1678 ||c_rec.owner
1679 ||'.'
1680 ||c_rec.table_name
1681 ||'. Stats were gathered.' );
1682 ELSE
1683 dlog('Monitoring is not enabled for Table '
1684 ||c_rec.owner
1685 ||'.'
1686 ||c_rec.table_name );
1687 END IF;
1688 END LOOP; -- nomon_tab
1689 elsif ( (upper(OPTIONS)='GATHER EMPTY') OR
1690 (
1691 upper(OPTIONS)='LIST EMPTY'
1692 )
1693 ) THEN
1694 FOR c_rec IN empty_cur(upper(schemaname))
1695 LOOP
1696 IF c_rec.type = 'TABLE' THEN
1697 IF (upper(OPTIONS)='GATHER EMPTY') THEN
1698 FND_STATS.GATHER_TABLE_STATS(ownname => c_rec.owner, tabname => c_rec.name,
1699 percent => NVL(estimate_percent,10), degree => degree_parallel, partname=>NULL, CASCADE => TRUE,
1700 granularity => granularity, hmode => stathist, invalidate=> invalidate );
1701 ELSE
1702 dlog('Table '
1703 ||c_rec.owner
1704 ||'.'
1705 ||c_rec.name
1706 ||' is missing statistics! ');
1707 END IF;
1708 END IF;
1709 END LOOP;
1710 FOR rec_cur IN lock_stats_tab(upper(schemaname)) -- added by saleem to display warning for tables with locked stats
1711 LOOP
1712 dbms_output.put_line('stats on table '
1713 || rec_cur.table_name
1714 || ' is locked ');
1715 dlog('stats on table '
1716 || rec_cur.table_name
1717 || ' is locked ');
1718 -- s_message := 'stats on table ' || rec_cur.table_name || ' is locked ' ;
1719 --fnd_file.put_line(FND_FILE.log,s_message);
1720 END LOOP;
1721 END IF;
1722 /* end of if upper(options)= */
1723 -- End timestamp
1724 IF(upper(stathist) <> 'NONE') THEN
1725 BEGIN
1726 FND_STATS.UPDATE_HIST(schemaname=>schemaname, objectname=>schemaname, objecttype=>'SCHEMA', partname=>NULL, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'E' );
1727 END;
1728 END IF;
1729 ELSE
1730 /* This is for ALL schema */
1731 FOR c_schema IN schema_cur
1732 LOOP
1733 --dbms_output.put_line('start of schema = '|| c_schema.sname);
1734 -- make a recursive call to gather_schema_stats
1735 GATHER_SCHEMA_STATS(schemaname=>c_schema.sname , estimate_percent=>estimate_percent , degree=>degree , internal_flag=>internal_flag ,
1736 --Errors=> Errors ,-- commented for error handling
1737 request_id=>request_id , hmode=>stathist , OPTIONS=>OPTIONS , modpercent=>modpercent , invalidate=> invalidate );
1738 END LOOP;
1739 /* schema_cur */
1740 END IF;
1741 ELSE -- schema is SYS, print message in log.
1745 END;
1742 dlog('Gathering statistics on the SYS schema using FND_STATS is not allowed.');
1743 dlog('Please use DBMS_STATS package to gather stats on SYS objects.');
1744 END IF; -- end of schema<> SYS
1746 /* GATHER_SCHEMA_STATS */
1747 /************************************************************************/
1748 /* Procedure: GATHER_INDEX_STATS */
1749 /* Desciption: Gathers stats for a particular index. */
1750 /************************************************************************/
1751 PROCEDURE GATHER_INDEX_STATS(ownname IN VARCHAR2,
1752 indname IN VARCHAR2,
1753 percent IN NUMBER DEFAULT NULL,
1754 degree IN NUMBER DEFAULT NULL,
1755 partname IN VARCHAR2 DEFAULT NULL,
1756 backup_flag IN VARCHAR2 ,
1757 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
1758 invalidate IN VARCHAR2 DEFAULT 'Y' )
1759 IS
1760 num_blks NUMBER;
1761 adj_percent NUMBER ; -- adjusted percent based on table blocks.
1762 exist_insufficient EXCEPTION;
1763 pragma exception_init(exist_insufficient,-20002);
1764 degree_parallel NUMBER(4) ;
1765 BEGIN
1766 -- Set the package body variable.
1767 stathist := hmode;
1768 num_blks := fnd_stats.get_blocks(ownname,indname,'INDEX');
1769 -- In 8i, you cannot provide a degree for an index, in 9iR2 we can.
1770 IF num_blks <= SMALL_IND_FOR_PAR_THOLD THEN
1771 degree_parallel:=1;
1772 ELSE
1773 IF degree IS NULL THEN
1774 degree_parallel:=def_degree;
1775 ELSE
1776 degree_parallel :=degree;
1777 END IF;
1778 END IF;
1779 -- For better stats, indexes smaller than small_ind_for_est_thold
1780 -- should be gathered at 100%.
1781 IF num_blks <= SMALL_IND_FOR_EST_THOLD THEN
1782 IF ((db_versn>80) AND
1783 (
1784 db_versn < 90
1785 )
1786 ) THEN -- w/a for bug 1998176
1787 adj_percent:=99.99;
1788 ELSE
1789 adj_percent:=100;
1790 END IF;
1791 ELSE
1792 adj_percent:=percent;
1793 END IF;
1794 -- Insert/update the fnd_stat_hist table
1795 IF(upper(stathist) <> 'NONE') THEN
1796 BEGIN
1797 FND_STATS.UPDATE_HIST(schemaname=>upper(ownname), objectname=>upper(indname), objecttype=>'INDEX', partname=>upper(partname), columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'S', percent=>NVL(adj_percent,10));
1798 END;
1799 END IF;
1800 -- backup the existing index stats
1801 IF ( upper(NVL(backup_flag,'NOBACKUP')) = 'BACKUP' ) THEN
1802 -- First create the FND_STATTAB if it doesn't exist.
1803 BEGIN
1804 FND_STATS.CREATE_STAT_TABLE();
1805 EXCEPTION
1806 WHEN exist_insufficient THEN
1807 NULL;
1808 END;
1809 DBMS_STATS.EXPORT_INDEX_STATS( ownname, indname, NULL, fnd_stattab, NULL, fnd_statown );
1810 END IF;
1811 FND_STATS.GATHER_INDEX_STATS_PVT(ownname => ownname, indname => indname, partname => partname, estimate_percent => NVL(adj_percent,10), degree=>degree_parallel, invalidate => invalidate ) ;
1812 -- End timestamp
1813 IF(upper(stathist) <> 'NONE') THEN
1814 BEGIN
1815 -- update fnd_stats_hist for completed stats
1816 FND_STATS.UPDATE_HIST(schemaname=>upper(ownname), objectname=>upper(indname), objecttype=>'INDEX', partname=>upper(partname), columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'E' );
1817 END;
1818 END IF;
1819 END ;
1820 /* GATHER_INDEX_STATS */
1821 /************************************************************************/
1822 /* Procedure: GATHER_TABLE_STATS */
1823 /* Desciption: Gathers stats for a particular table. Concurrent program */
1824 /* version. */
1825 /************************************************************************/
1826 PROCEDURE GATHER_TABLE_STATS(errbuf OUT NOCOPY VARCHAR2,
1827 retcode OUT NOCOPY VARCHAR2,
1828 ownname IN VARCHAR2,
1829 tabname IN VARCHAR2,
1830 percent IN NUMBER,
1831 degree IN NUMBER,
1832 partname IN VARCHAR2,
1833 backup_flag IN VARCHAR2,
1834 granularity IN VARCHAR2,
1835 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
1836 invalidate IN VARCHAR2 DEFAULT 'Y' )
1837 IS
1838 exist_insufficient EXCEPTION;
1839 pragma exception_init(exist_insufficient,-20000);
1843 granularity,hmode,invalidate);
1840 l_message VARCHAR2(1000);
1841 BEGIN
1842 FND_STATS.GATHER_TABLE_STATS(ownname, tabname, percent, degree, partname, backup_flag, true,
1844 EXCEPTION
1845 WHEN exist_insufficient THEN
1846 errbuf := sqlerrm ;
1847 retcode := '2';
1848 l_message := errbuf;
1849 FND_FILE.put_line(FND_FILE.log,l_message);
1850 raise;
1851 WHEN OTHERS THEN
1852 errbuf := sqlerrm ;
1853 retcode := '2';
1854 l_message := errbuf;
1855 FND_FILE.put_line(FND_FILE.log,l_message);
1856 raise;
1857 END;
1858 /* GATHER_TABLE_STATS */
1859 /************************************************************************/
1860 /* Procedure: GATHER_TABLE_STATS */
1861 /* Desciption: Gathers stats for a particular table. Called by */
1862 /* Concurrent program version. */
1863 /************************************************************************/
1864 PROCEDURE GATHER_TABLE_STATS(ownname IN VARCHAR2,
1865 tabname IN VARCHAR2,
1866 percent IN NUMBER,
1867 degree IN NUMBER,
1868 partname IN VARCHAR2,
1869 backup_flag IN VARCHAR2,
1870 CASCADE IN BOOLEAN,
1871 granularity IN VARCHAR2,
1872 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
1873 invalidate IN VARCHAR2 DEFAULT 'Y' )
1874 IS
1875 cascade_true BOOLEAN := TRUE;
1876 approx_num_rows NUMBER ;
1877 num_blks NUMBER;
1878 adj_percent NUMBER ; -- adjusted percent based on table blocks.
1879 num_ind_rows NUMBER;
1880 obj_type VARCHAR2(7);
1881 method VARCHAR2(2000) ;
1882 exist_insufficient EXCEPTION;
1883 pragma exception_init(exist_insufficient,-20002);
1884 -- New cursor to support MVs
1885 CURSOR col_cursor (ownname VARCHAR2, tabname VARCHAR2, partname VARCHAR2)
1886 IS
1887 SELECT a.column_name,
1888 NVL(a.hsize,254) hsize
1889 FROM FND_HISTOGRAM_COLS a
1890 WHERE a.table_name = upper(tabname)
1891 AND
1892 (
1893 a.partition = upper(partname)
1894 OR partname IS NULL
1895 )
1896 ORDER BY a.column_name;
1897
1898 CURSOR ind_cursor(ownname VARCHAR2,tabname VARCHAR2)
1899 IS
1900 SELECT a.index_name indname,
1901 a.owner indowner ,
1902 a.uniqueness uniq
1903 FROM dba_indexes a
1904 WHERE table_name = upper(tabname)
1905 AND table_owner= upper(ownname)
1906 ORDER BY index_name;
1907
1908 degree_parallel NUMBER(4);
1909 BEGIN
1910 -- Set the package body variable.
1911 stathist := hmode;
1912 num_blks :=fnd_stats.get_blocks(ownname,tabname,'TABLE');
1913 -- For better performance, tables smaller than small_tab_for_par_thold should be gathered in serial.
1914 IF num_blks <= SMALL_TAB_FOR_PAR_THOLD THEN
1915 degree_parallel:=1;
1916 elsif degree IS NULL THEN -- degree will not be null when called from gather_schema_stats
1917 degree_parallel:=def_degree;
1918 ELSE
1919 degree_parallel := degree;
1920 END IF;
1921 -- For better stats, tables smaller than small_tab_for_est_thold
1922 -- should be gathered at 100%.
1923 IF num_blks <= SMALL_TAB_FOR_EST_THOLD THEN
1924 IF ((db_versn>80) AND
1925 (
1926 db_versn < 90
1927 )
1928 ) THEN -- w/a for bug 1998176
1929 adj_percent:=99.99;
1930 ELSE
1931 adj_percent:=100;
1932 END IF;
1933 ELSE
1934 adj_percent:=percent;
1935 END IF;
1936 -- Insert/update the fnd_stat_hist table
1937 -- change to call update_hist for autonomous_transaction
1938 IF (CASCADE) THEN
1939 obj_type:='CASCADE';
1940 ELSE
1941 obj_type := 'TABLE';
1942 END IF;
1943 IF(upper(stathist) <> 'NONE') THEN
1944 BEGIN
1945 -- if(cur_request_id is null) then
1946 -- cur_request_id := GET_REQUEST_ID(null); -- for gather table stats, we will not have a request_id
1947 -- end if;
1948 FND_STATS.UPDATE_HIST(schemaname=>ownname, objectname=>tabname, objecttype=>obj_type, partname=>partname, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'S', percent=>NVL(adj_percent,10));
1949 EXCEPTION
1950 WHEN OTHERS THEN
1951 raise;
1952 END;
1953 END IF;
1954 -- backup the existing table stats
1955 IF ( upper(NVL(backup_flag,'NOBACKUP')) = 'BACKUP' ) THEN
1956 BEGIN
1960 EXCEPTION
1957 -- First create the FND_STATTAB if it doesn't exist.
1958 BEGIN
1959 FND_STATS.CREATE_STAT_TABLE();
1961 WHEN exist_insufficient THEN
1962 NULL;
1963 END;
1964 DBMS_STATS.EXPORT_TABLE_STATS(ownname, tabname, partname, fnd_stattab,NULL,CASCADE,fnd_statown );
1965 EXCEPTION
1966 WHEN OTHERS THEN
1967 raise;
1968 END;
1969 END IF;
1970 IF (db_versn >= 92) THEN
1971 --Build up the method_opt if histogram cols are present
1972 method := ' FOR COLUMNS ' ;
1973 FOR c_rec IN col_cursor(ownname,tabname,partname)
1974 LOOP
1975 method := method
1976 ||' '
1977 || c_rec.column_name
1978 ||' SIZE '
1979 || c_rec.hsize ;
1980 END LOOP;
1981 -- If no histogram cols then nullify method ;
1982 IF method = ' FOR COLUMNS ' THEN
1983 method := 'FOR ALL COLUMNS SIZE 1' ;
1984 END IF;
1985 IF (method = 'FOR ALL COLUMNS SIZE 1') THEN
1986 BEGIN
1987 --dbms_output.put_line('SINGLE:'||method||'granularity='||granularity);
1988 FND_STATS.GATHER_TABLE_STATS_PVT(ownname => ownname, tabname => tabname,
1989 partname => partname, method_opt => method, estimate_percent => NVL(adj_percent,10), degree => degree_parallel,
1990 CASCADE => CASCADE, granularity => granularity, invalidate=> invalidate );
1991 EXCEPTION
1992 WHEN OTHERS THEN
1993 -- dbms_output.put_line('about to raise'||sqlcode||' --- '||sqlerrm);
1994 -- Error code for external table error is ora-20000 which is the same as the code
1995 -- for exist_insufficient error. Because of that, we have to resort to the following
1996 -- if check on the error message.
1997 IF(SUBSTR(sqlerrm,instr(sqlerrm,',')+2)= 'sampling on external table is not supported') THEN
1998 NULL; -- Ignore this error because apps does not use External tables.
1999 ELSE
2000 raise;
2001 END IF;
2002 END;
2003 ELSE -- call it with histogram cols.
2004 BEGIN
2005 -- dbms_output.put_line('FOR ALL COLUMNS SIZE 1 '||method);
2006 FND_STATS.GATHER_TABLE_STATS_PVT(ownname => ownname, tabname => tabname, partname => partname, method_opt => 'FOR ALL COLUMNS SIZE 1 '
2007 ||method, estimate_percent => NVL(adj_percent,10), degree => degree_parallel, CASCADE => CASCADE, granularity => granularity, invalidate=> invalidate );
2008 EXCEPTION
2009 WHEN OTHERS THEN
2010 raise;
2011 END;
2012 END IF;
2013 ELSE -- version is pre 9.2, use the old method of calling twice.
2014 --Build up the method_opt if histogram cols are present
2015 method := ' FOR COLUMNS ' ;
2016 FOR c_rec IN col_cursor(ownname,tabname,partname)
2017 LOOP
2018 IF method <> ' FOR COLUMNS ' THEN
2019 method := method
2020 || ',' ;
2021 END IF;
2022 method := method
2023 ||' '
2024 || c_rec.column_name
2025 ||' SIZE '
2026 || c_rec.hsize ;
2027 END LOOP;
2028 -- If no histogram cols then nullify method ;
2029 IF method = ' FOR COLUMNS ' THEN
2030 method := 'FOR ALL COLUMNS SIZE 1' ;
2031 END IF;
2032 -- Due to the limitations of in DBMS_STATS in 8i we need to call
2033 -- FND_STATS.GATHER_TABLE_STATS twice, once for histogram
2034 -- and once for just the table stats.
2035 IF (method = 'FOR ALL COLUMNS SIZE 1') THEN
2036 BEGIN
2037 --dbms_output.put_line('SINGLE:'||method||'granularity='||granularity);
2038 FND_STATS.GATHER_TABLE_STATS_PVT(ownname => ownname, tabname => tabname,
2039 partname => partname, method_opt => method, estimate_percent => NVL(adj_percent,10), degree => degree_parallel,
2040 CASCADE => CASCADE, granularity => granularity, invalidate=> invalidate );
2041 EXCEPTION
2042 WHEN OTHERS THEN
2043 raise;
2044 END;
2045 ELSE -- call it twice
2046 BEGIN
2047 --dbms_output.put_line('DOUBLE 1:'||method||'granularity='||granularity);
2048 FND_STATS.GATHER_TABLE_STATS_PVT(ownname => ownname, tabname => tabname,
2049 partname => partname, method_opt => 'FOR ALL COLUMNS SIZE 1', estimate_percent => NVL(adj_percent,10),
2053 raise;
2050 degree => degree_parallel, CASCADE => CASCADE, granularity => granularity, invalidate=> invalidate );
2051 EXCEPTION
2052 WHEN OTHERS THEN
2054 END;
2055 BEGIN
2056 --dbms_output.put_line('DOUBLE 2:'||method||'granularity='||granularity);
2057 FND_STATS.GATHER_TABLE_STATS_PVT(ownname => ownname, tabname => tabname,
2058 partname => partname, method_opt => method, estimate_percent => NVL(adj_percent,10), degree => degree_parallel,
2059 CASCADE => FALSE, granularity => granularity, invalidate=> invalidate );
2060 EXCEPTION
2061 WHEN OTHERS THEN
2062 raise;
2063 END;
2064 END IF;
2065 END IF; -- db_versn is 8i
2066 -- End timestamp
2067 -- change to call update_hist for autonomous_transaction
2068 IF(upper(stathist) <> 'NONE') THEN
2069 BEGIN
2070 FND_STATS.UPDATE_HIST(schemaname=>ownname, objectname=>tabname, objecttype=>obj_type, partname=>partname, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'E' );
2071 EXCEPTION
2072 WHEN OTHERS THEN
2073 raise;
2074 END;
2075 END IF;
2076 END ;
2077 /* GATHER_TABLE_STATS */
2078 /************************************************************************/
2079 /* Procedure: GATHER_COLUMN_STATS */
2080 /* Desciption: Gathers stats for all columns in FND_HISTOGRAM_COLS table*/
2081 /************************************************************************/
2082 PROCEDURE GATHER_COLUMN_STATS(appl_id IN NUMBER DEFAULT NULL,
2083 percent IN NUMBER DEFAULT NULL,
2084 degree IN NUMBER DEFAULT NULL,
2085 backup_flag IN VARCHAR2 ,
2086 --Errors OUT NOCOPY Error_Out, -- commented for errorhandling
2087 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
2088 invalidate IN VARCHAR2 DEFAULT 'Y' )
2089 IS
2090 -- New cursor to support MVs
2091 CURSOR tab_cursor (appl_id NUMBER)
2092 IS
2093 SELECT DISTINCT a.application_id,
2094 a.table_name ,
2095 a.partition
2096 FROM FND_HISTOGRAM_COLS a
2097 WHERE
2098 (
2099 a.application_id = appl_id
2100 OR appl_id IS NULL
2101 )
2102 ORDER BY a.application_id,
2103 a.table_name;
2104
2105 -- New cursor to support MVs
2106 CURSOR col_cursor (appl_id NUMBER, tabname VARCHAR2, partname VARCHAR2)
2107 IS
2108 SELECT a.column_name ,
2109 NVL(a.hsize,254) hsize,
2110 NVL(a.owner, upper(b.oracle_username)) ownname
2111 FROM FND_HISTOGRAM_COLS a,
2112 FND_ORACLE_USERID b ,
2113 FND_PRODUCT_INSTALLATIONS c
2114 WHERE a.application_id = appl_id
2115 AND a.application_id = c.application_id (+)
2116 AND c.oracle_id = b.oracle_id (+)
2117 AND a.table_name = upper(tabname)
2118 AND
2119 (
2120 a.partition = upper(partname)
2121 OR partname IS NULL
2122 )
2123 ORDER BY a.column_name;
2124
2125 exist_insufficient EXCEPTION;
2126 pragma exception_init(exist_insufficient,-20002);
2127 owner VARCHAR2(30);
2128 i BINARY_INTEGER := 0;
2129 method VARCHAR2(2000);
2130 degree_parallel NUMBER (4);
2131 /* defind variables for the bulk fetch */
2132 TYPE num_list
2133 IS
2134 TABLE OF NUMBER(15) INDEX BY BINARY_INTEGER;
2135 TYPE char_list
2136 IS
2137 TABLE OF VARCHAR2(64) INDEX BY BINARY_INTEGER;
2138 list_column_name char_list;
2139 list_hsize num_list;
2140 list_ownname char_list;
2141 BEGIN
2142 -- Set the package body variable.
2143 stathist := hmode;
2144 IF degree IS NULL THEN
2145 degree_parallel:=def_degree;
2146 ELSE
2147 degree_parallel := degree;
2148 END IF;
2149 -- Initialize the TABLE Errors
2150 --Errors(0) := NULL; -- commented for stopping the initialization
2151 FOR t_rec IN tab_cursor(appl_id)
2152 LOOP
2153 method := ' FOR COLUMNS ';
2154 /* initialize method_opt variable */
2155 /* Bulk fetch data from col_cursor and loop through it */
2156 OPEN col_cursor (t_rec.application_id,t_rec.table_name, t_rec.partition);
2157 FETCH col_cursor BULK COLLECT
2158 INTO list_column_name,
2159 list_hsize ,
2160 list_ownname;
2161
2162 CLOSE col_cursor;
2163 FOR i IN 1..list_column_name.last
2164 LOOP
2165 IF(upper(stathist) <> 'NONE') THEN
2166 BEGIN
2170 -- First export the col stats depending on backup-flag
2167 FND_STATS.UPDATE_HIST(schemaname=>list_ownname(i), objectname=>list_column_name(i), objecttype=>'COLUMN', partname=>t_rec.partition, columntablename=>t_rec.table_name, degree=>degree_parallel, upd_ins_flag=>'S' );
2168 END;
2169 END IF;
2171 IF ( upper(NVL(backup_flag,'NOBACKUP')) = 'BACKUP') THEN
2172 BEGIN
2173 -- First create the FND_STATTAB if it doesn't exist.
2174 BEGIN
2175 FND_STATS.CREATE_STAT_TABLE();
2176 EXCEPTION
2177 WHEN exist_insufficient THEN
2178 NULL;
2179 END;
2180 DBMS_STATS.EXPORT_COLUMN_STATS(list_ownname(i), t_rec.table_name, list_column_name(i), t_rec.partition, fnd_stattab, NULL, fnd_statown);
2181 END;
2182 END IF;
2183 -- Build up the method_opt variable
2184 IF (method <> ' FOR COLUMNS ') THEN
2185 method := method
2186 || ',';
2187 END IF;
2188 method := method
2189 || list_column_name(i)
2190 ||' SIZE '
2191 || list_hsize(i);
2192 owner := list_ownname(i);
2193 END LOOP;
2194 /* end of c_rec */
2195 BEGIN
2196 FND_STATS.GATHER_TABLE_STATS_PVT(ownname => owner, tabname => t_rec.table_name,
2197 partname => t_rec.partition, estimate_percent => NVL(percent,10), method_opt => method,
2198 degree => degree_parallel, CASCADE => FALSE, invalidate=> invalidate, stattab => fnd_stattab,
2199 statown => fnd_statown);
2200 -- now that histograms are collected update fnd_stats_hist
2201 IF(upper(stathist) <> 'NONE') THEN
2202 FOR i IN 1..list_column_name.last
2203 LOOP
2204 FND_STATS.UPDATE_HIST(schemaname=>list_ownname(i), objectname=>list_column_name(i), objecttype=>'COLUMN', partname=>t_rec.partition, columntablename=>t_rec.table_name, degree=>degree_parallel, upd_ins_flag=>'E' );
2205 END LOOP;
2206 END IF;
2207 EXCEPTION
2208 WHEN OTHERS THEN
2209 g_Errors(i) := 'ERROR: In GATHER_COLUMN_STATS: '
2210 ||SQLERRM ;
2211 g_Errors(i+1) := NULL;
2212 i := i+1;
2213 END;
2214 /* end of FND_STATS.GATHER_TABLE_STATS_PVT call */
2215 END LOOP;
2216 /* end of t_rec */
2217 END;
2218 /* end of procedure GATHER_COLUMN_STATS */
2219 /************************************************************************/
2220 /* Procedure: GATHER_ALL_COLUMN_STATS */
2221 /* Desciption: Gathers cols stats for a given schema */
2222 /* or if ownname = 'ALL' then for ALL apps schema */
2223 /************************************************************************/
2224 PROCEDURE GATHER_ALL_COLUMN_STATS(ownname IN VARCHAR2,
2225 percent IN NUMBER DEFAULT NULL,
2226 degree IN NUMBER DEFAULT NULL,
2227 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
2228 invalidate IN VARCHAR2 DEFAULT 'Y' )
2229 IS
2230 -- New cursor for MVs
2231 CURSOR tab_cursor (ownname VARCHAR2)
2232 IS
2233 SELECT DISTINCT a.table_name,
2234 a.application_id
2235 FROM FND_HISTOGRAM_COLS a,
2236 FND_ORACLE_USERID b ,
2237 FND_PRODUCT_INSTALLATIONS c
2238 WHERE
2239 (
2240 b.oracle_username= upper(ownname)
2241 OR a.owner =upper(ownname)
2242 )
2243 AND a.application_id = c.application_id (+)
2244 AND c.oracle_id = b.oracle_id (+)
2245 ORDER BY 2 ,
2246 1;
2247
2248 CURSOR col_cursor (appl_id NUMBER, tabname VARCHAR2)
2249 IS
2250 SELECT column_name,
2251 NVL(hsize,254) hsize
2252 FROM FND_HISTOGRAM_COLS a
2253 WHERE a.application_id = appl_id
2254 AND a.table_name = upper(tabname)
2255 ORDER BY 1 ;
2256
2257 method VARCHAR2(2000) ;
2258 degree_parallel NUMBER (4);
2259 BEGIN
2260 -- Set the package body variable.
2261 stathist := hmode;
2262 IF degree IS NULL THEN
2263 degree_parallel:=def_degree;
2264 ELSE
2265 degree_parallel := degree;
2266 END IF;
2267 -- If a specific schema is given
2271 LOOP
2268 IF (upper(ownname) <> 'ALL') THEN
2269 -- get the tables for the given schema
2270 FOR t_rec IN tab_cursor(ownname)
2272 -- Insert/update the fnd_stats_hist table
2273 --dbms_output.put_line('appl_id = '||t_rec.application_id||',table='||t_rec.table_name);
2274 IF(upper(stathist) <> 'NONE') THEN
2275 BEGIN
2276 FND_STATS.UPDATE_HIST(schemaname=>ownname, objectname=>ownname, objecttype=>'HIST', partname=>NULL, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'S' );
2277 END;
2278 END IF;
2279 -- get the column list and build up the METHOD_OPT
2280 method := ' FOR COLUMNS ';
2281 FOR c_rec IN col_cursor(t_rec.application_id, t_rec.table_name)
2282 LOOP
2283 -- Build up the method_opt variable
2284 IF (method <> ' FOR COLUMNS ') THEN
2285 method := method
2286 || ',';
2287 END IF;
2288 method := method
2289 || c_rec.column_name
2290 ||' SIZE '
2291 || c_rec.hsize;
2292 END LOOP ;
2293 /* c_rec */
2294 --dbms_output.put_line(' method = '|| method);
2295 BEGIN
2296 FND_STATS.GATHER_TABLE_STATS_PVT ( ownname => ownname, tabname => t_rec.table_name, estimate_percent => NVL(percent,10), method_opt => method, degree => degree_parallel, CASCADE => FALSE, invalidate => invalidate );
2297 EXCEPTION
2298 WHEN OTHERS THEN
2299 raise;
2300 END;
2301 /* end of FND_STATS.GATHER_TABLE_STATS_PVT call */
2302 -- End timestamp
2303 IF(upper(stathist) <> 'NONE') THEN
2304 BEGIN
2305 FND_STATS.UPDATE_HIST(schemaname=>ownname, objectname=>ownname, objecttype=>'HIST', partname=>NULL, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'E' );
2306 END;
2307 END IF;
2308 END LOOP ;
2309 /* t_rec */
2310 ELSE
2311 /* ownname = 'ALL' */
2312 FOR s_rec IN schema_cur
2313 LOOP
2314 --dbms_output.put_line('start of schema = '|| s_rec.sname);
2315 -- get the tables for the given schema
2316 FOR t_rec IN tab_cursor(s_rec.sname)
2317 LOOP
2318 -- Insert/update the fnd_stat_hist table
2319 --dbms_output.put_line('appl_id = '||t_rec.application_id||',table='||t_rec.table_name);
2320 IF(upper(stathist) <> 'NONE') THEN
2321 BEGIN
2322 FND_STATS.UPDATE_HIST(schemaname=>s_rec.sname, objectname=>s_rec.sname, objecttype=>'HIST', partname=>NULL, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'S' );
2323 END;
2324 END IF;
2325 -- get the column list and build up the METHOD_OPT
2326 method := ' FOR COLUMNS ';
2327 FOR c_rec IN col_cursor(t_rec.application_id, t_rec.table_name)
2328 LOOP
2329 -- Build up the method_opt variable
2330 IF (method <> ' FOR COLUMNS ') THEN
2331 method := method
2332 || ',';
2333 END IF;
2334 method := method
2335 || c_rec.column_name
2336 ||' SIZE '
2337 || c_rec.hsize;
2338 END LOOP ;
2339 /* c_rec */
2340 --dbms_output.put_line(' method = '|| method);
2341 BEGIN
2342 FND_STATS.GATHER_TABLE_STATS_PVT ( ownname => s_rec.sname,
2343 tabname => t_rec.table_name, estimate_percent => NVL(percent,10), method_opt => method,
2344 degree => degree_parallel, CASCADE => FALSE, invalidate => invalidate );
2345 EXCEPTION
2346 WHEN OTHERS THEN
2347 raise;
2348 END;
2349 /* end of FND_STATS.GATHER_TABLE_STATS_PVT call */
2350 -- End timestamp
2351 IF(upper(stathist) <> 'NONE') THEN
2352 BEGIN
2353 FND_STATS.UPDATE_HIST(schemaname=>s_rec.sname, objectname=>s_rec.sname, objecttype=>'HIST', partname=>NULL, columntablename=>NULL, degree=>degree_parallel, upd_ins_flag=>'S' );
2357 /* t_rec */
2354 END;
2355 END IF;
2356 END LOOP ;
2358 END LOOP ;
2359 /* s_rec */
2360 END IF ;
2361 /* end of ownname='ALL' */
2362 END;
2363 /* end of GATHER_ALL_COLUMN_STATS */
2364 /************************************************************************/
2365 /* Procedure: GATHER_ALL_COLUMN_STATS */
2366 /* Desciption: Gathers cols stats for a given schema */
2367 /* or if ownname = 'ALL' then for ALL apps schema. This the concurrent */
2368 /* program manager version */
2369 /************************************************************************/
2370 PROCEDURE GATHER_ALL_COLUMN_STATS(errbuf OUT NOCOPY VARCHAR2,
2371 retcode OUT NOCOPY VARCHAR2,
2372 ownname IN VARCHAR2,
2373 percent IN NUMBER DEFAULT NULL,
2374 degree IN NUMBER DEFAULT NULL,
2375 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
2376 invalidate IN VARCHAR2 DEFAULT 'Y' )
2377 IS
2378 l_message VARCHAR2(2000);
2379 BEGIN
2380 -- Set the package body variable.
2381 stathist := hmode;
2382 FND_STATS.GATHER_ALL_COLUMN_STATS(ownname=>ownname,percent=>percent,degree=>degree,hmode=>stathist,invalidate=>invalidate);
2383 EXCEPTION
2384 WHEN OTHERS THEN
2385 errbuf := sqlerrm ;
2386 retcode := '2';
2387 l_message := errbuf;
2388 FND_FILE.put_line(FND_FILE.log,l_message);
2389 raise;
2390 END;
2391 /* end of conc mgr GATHER_ALL_COLUMN_STATS */
2392 /************************************************************************/
2393 /* Procedure: GATHER_COLUMN_STATS */
2394 /* Desciption: Gathers cols stats This the concurrent program manager */
2395 /* version */
2396 /************************************************************************/
2397 PROCEDURE GATHER_COLUMN_STATS(errbuf OUT NOCOPY VARCHAR2,
2398 retcode OUT NOCOPY VARCHAR2,
2399 ownname IN VARCHAR2,
2400 tabname IN VARCHAR2,
2401 colname IN VARCHAR2,
2402 percent IN NUMBER DEFAULT NULL,
2403 degree IN NUMBER DEFAULT NULL,
2404 hsize IN NUMBER DEFAULT 254,
2405 backup_flag IN VARCHAR2 ,
2406 partname IN VARCHAR2 DEFAULT NULL,
2407 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
2408 invalidate IN VARCHAR2 DEFAULT 'Y' )
2409 IS
2410 exist_insufficient EXCEPTION;
2411 pragma exception_init(exist_insufficient,-20000);
2412 l_message VARCHAR2(1000);
2413 BEGIN
2414 -- Set the package body variable.
2415 stathist := hmode;
2416 l_message := 'In GATHER_COLUMN_STATS , column is '
2417 || ownname
2418 ||'.'
2419 ||tabname
2420 ||'.'
2421 ||colname
2422 ||' backup_flag= '
2423 || backup_flag ;
2424 FND_FILE.put_line(FND_FILE.log,l_message);
2425 dlog(l_message);
2426 BEGIN
2427 dlog('about to g c s');
2428 FND_STATS.GATHER_COLUMN_STATS(ownname,tabname,colname,percent,degree ,hsize,backup_flag,partname,hmode,invalidate);
2429 EXCEPTION
2430 WHEN exist_insufficient THEN
2431 errbuf := sqlerrm ;
2432 retcode := '2';
2433 l_message := errbuf;
2434 FND_FILE.put_line(FND_FILE.log,l_message);
2435 raise;
2436 WHEN OTHERS THEN
2437 errbuf := sqlerrm ;
2438 retcode := '2';
2439 l_message := errbuf;
2440 FND_FILE.put_line(FND_FILE.log,l_message);
2441 raise;
2442 END;
2443 END;
2444 /* end of GATHER_COLUMN_STATS for conc. job */
2445 /************************************************************************/
2446 /* Procedure: GATHER_COLUMN_STATS */
2447 /* Desciption: Gathers cols stats. */
2448 /************************************************************************/
2449 PROCEDURE GATHER_COLUMN_STATS(ownname IN VARCHAR2,
2450 tabname IN VARCHAR2,
2451 colname IN VARCHAR2,
2452 percent IN NUMBER DEFAULT NULL,
2453 degree IN NUMBER DEFAULT NULL,
2454 hsize IN NUMBER DEFAULT 254,
2455 backup_flag IN VARCHAR2 ,
2456 partname IN VARCHAR2 DEFAULT NULL,
2457 hmode IN VARCHAR2 DEFAULT 'LASTRUN',
2458 invalidate IN VARCHAR2 DEFAULT 'Y' )
2459 IS
2460 method VARCHAR2(200);
2461 exist_insufficient EXCEPTION;
2462 pragma exception_init(exist_insufficient,-20002);
2466 -- Set the package body variable.
2463 degree_parallel NUMBER (4);
2464 BEGIN
2465 dlog('about to g c s no cm version');
2467 stathist := hmode;
2468 IF degree IS NULL THEN
2469 degree_parallel:=def_degree;
2470 ELSE
2471 degree_parallel := degree;
2472 END IF;
2473 -- Insert/update the fnd_stat_hist table
2474 IF(upper(stathist) <> 'NONE') THEN
2475 BEGIN
2476 FND_STATS.UPDATE_HIST(schemaname=>ownname, objectname=>colname, objecttype=>'COLUMN', partname=>partname, columntablename=>tabname, degree=>degree_parallel, upd_ins_flag=>'S' );
2477 END;
2478 END IF;
2479 -- First export the col stats depending on the backup_flag
2480 IF ( upper(NVL(backup_flag,'NOBACKUP')) = 'BACKUP' ) THEN
2481 BEGIN
2482 -- First create the FND_STATTAB if it doesn't exist.
2483 BEGIN
2484 FND_STATS.CREATE_STAT_TABLE();
2485 EXCEPTION
2486 WHEN exist_insufficient THEN
2487 NULL;
2488 END;
2489 DBMS_STATS.EXPORT_COLUMN_STATS ( ownname, tabname, colname, partname, fnd_stattab, NULL, fnd_statown );
2490 END;
2491 END IF;
2492 -- Now gather statistics
2493 method := 'FOR COLUMNS SIZE '
2494 || hsize
2495 || ' '
2496 || colname;
2497 FND_STATS.GATHER_TABLE_STATS_PVT ( ownname => ownname, tabname => tabname, partname =>partname,
2498 estimate_percent => NVL(percent,10), method_opt => method, degree => degree_parallel, CASCADE => FALSE,
2499 stattab => fnd_stattab, statown => fnd_statown, invalidate => invalidate);
2500 -- End timestamp
2501 IF(upper(stathist) <> 'NONE') THEN
2502 BEGIN
2503 FND_STATS.UPDATE_HIST(schemaname=>ownname, objectname=>colname, objecttype=>'COLUMN', partname=>NULL, columntablename=>tabname, degree=>degree_parallel, upd_ins_flag=>'E' );
2504 END;
2505 END IF;
2506 END;
2507 /* GATHER_COLUMN_STATS */
2508 /************************************************************************/
2509 /* Procedure: SET_TABLE_STATS */
2510 /* Desciption: Sets table stats to certain values. */
2511 /************************************************************************/
2512 PROCEDURE SET_TABLE_STATS(ownname IN VARCHAR2,
2513 tabname IN VARCHAR2,
2514 numrows IN NUMBER,
2515 numblks IN NUMBER,
2516 avgrlen IN NUMBER,
2517 partname IN VARCHAR2 DEFAULT NULL )
2518 IS
2519 -- PRAGMA AUTONOMOUS_TRANSACTION ;
2520 BEGIN
2521 DBMS_STATS.SET_TABLE_STATS(ownname, tabname, partname, NULL, NULL, numrows, numblks, avgrlen, NULL, NULL);
2522 END;
2523 /* SET_TABLE_STATS */
2524 /************************************************************************/
2525 /* Procedure: SET_INDEX_STATS */
2526 /* Desciption: Sets index stats to certain values. */
2527 /************************************************************************/
2528 PROCEDURE SET_INDEX_STATS(ownname IN VARCHAR2,
2529 indname IN VARCHAR2,
2530 numrows IN NUMBER,
2531 numlblks IN NUMBER,
2532 numdist IN NUMBER,
2533 avglblk IN NUMBER,
2534 avgdblk IN NUMBER,
2535 clstfct IN NUMBER,
2536 indlevel IN NUMBER,
2537 partname IN VARCHAR2 DEFAULT NULL)
2538 IS
2539 l_iot VARCHAR2(5):='FALSE';
2540 l_clstfct NUMBER :=clstfct;
2541 BEGIN
2542 /* add this to fix bug # .....
2543 when the index is of type IOT, set clustering factor to zero
2544 */
2545 /* added to fix bug 2239903 */
2546 SELECT DECODE(index_type,'IOT - TOP', 'TRUE', 'FALSE')
2547 INTO l_iot
2548 FROM dba_indexes
2549 WHERE owner = ownname
2550 AND index_name = indname;
2551
2552 IF (l_iot = 'TRUE') THEN
2553 l_clstfct := 0;
2554 END IF;
2555 DBMS_STATS.SET_INDEX_STATS(ownname, indname, partname, NULL, NULL, numrows, numlblks, numdist, avglblk, avgdblk, l_clstfct, indlevel, NULL, NULL);
2556 EXCEPTION
2557 WHEN OTHERS THEN
2558 NULL;
2559 END;
2560 /* SET_INDEX_STATS */
2561 /******************************************************************************/
2562 /* Procedure: LOAD_XCLUD_TAB */
2563 /* Desciption: This procedure was deprecated, but 11.5.2CU2 onwards */
2564 /* we are reuseing it for a different purpose. This procedure */
2565 /* will be used to populate fnd_exclude_table_stats table , which */
2566 /* which contains the list of tables which should be skipped */
2567 /* by the gather schema stats program. */
2568 /******************************************************************************/
2569 PROCEDURE LOAD_XCLUD_TAB(action IN VARCHAR2,
2570 appl_id IN NUMBER,
2571 tabname IN VARCHAR2)
2572 IS
2576 (
2573 exist_flag VARCHAR2(6) := NULL;
2574 BEGIN
2575 IF ((Upper(action) = 'INSERT') OR
2577 Upper(action) = 'INS'
2578 )
2579 OR
2580 (
2581 Upper(action) = 'I'
2582 )
2583 ) THEN
2584 -- Check for existence of the table first in FND Dictionary
2585 -- then in data dictionary
2586 -- break out if it doesn't exist
2587 BEGIN
2588 SELECT 'EXIST'
2589 INTO exist_flag
2590 FROM fnd_tables a
2591 WHERE a.table_name = upper(tabname)
2592 AND a.application_id = appl_id ;
2593
2594 EXCEPTION
2595 WHEN no_data_found THEN
2596 BEGIN
2597 SELECT 'EXIST'
2598 INTO exist_flag
2599 FROM dba_tables
2600 WHERE table_name = upper(tabname)
2601 AND owner =
2602 ( SELECT b.oracle_username
2603 FROM fnd_product_installations a,
2604 fnd_oracle_userid b
2605 WHERE a.application_id = appl_id
2606 AND b.oracle_id = a.oracle_id
2607 );
2608
2609 EXCEPTION
2610 WHEN no_data_found THEN
2611 raise_application_error(-20000, 'Table '
2612 || tabname
2613 || ' does not exist in fnd_tables/dba_tables for the
2614 given application ');
2615 END;
2616 END;
2617 -- Now insert
2618 INSERT
2619 INTO FND_EXCLUDE_TABLE_STATS
2620 (
2621 APPLICATION_ID ,
2622 TABLE_NAME ,
2623 CREATION_DATE ,
2624 CREATED_BY ,
2625 LAST_UPDATE_DATE,
2626 LAST_UPDATED_BY ,
2627 LAST_UPDATE_LOGIN
2628 )
2629 VALUES
2630 (
2631 appl_id ,
2632 upper(tabname),
2633 sysdate ,
2634 1 ,
2635 sysdate ,
2636 1 ,
2637 NULL
2638 ) ;
2639
2640 elsif ((Upper(action) = 'DELETE') OR
2641 (
2642 Upper(action) = 'DEL'
2643 )
2644 OR
2645 (
2646 Upper(action) = 'D'
2647 )
2648 ) THEN
2649 DELETE
2650 FROM FND_EXCLUDE_TABLE_STATS
2651 WHERE table_name = upper(tabname)
2652 AND application_id = appl_id;
2653
2654 END IF;
2655 COMMIT;
2656 END;
2657 /* LOAD_XCLUD_TAB */
2658 /************************************************************************/
2659 /* Procedure: LOAD_HISTOGRAM_COLS */
2660 /* Desciption: This is for internal purpose only. For loading into */
2661 /* SEED database */
2662 /************************************************************************/
2663 PROCEDURE LOAD_HISTOGRAM_COLS(action IN VARCHAR2,
2664 appl_id IN NUMBER,
2665 tabname IN VARCHAR2,
2666 colname IN VARCHAR2,
2667 partname IN VARCHAR2 DEFAULT NULL,
2668 hsize IN NUMBER DEFAULT 254,
2669 commit_flag IN VARCHAR2 DEFAULT 'Y')
2670 IS
2671 exist_flag VARCHAR2(5) := NULL;
2672 BEGIN
2673 IF upper(action) = 'INSERT' THEN
2674 BEGIN
2675 -- Check for existence of the table first
2676 -- break out if it doesn't exist
2677 BEGIN
2678 SELECT DISTINCT('EXIST')
2679 INTO exist_flag
2680 FROM dba_tab_columns a ,
2681 fnd_oracle_userid b,
2682 fnd_product_installations c
2683 WHERE a.table_name = upper(tabname)
2684 AND a.column_name = upper(colname)
2685 AND c.application_id = appl_id
2686 AND c.oracle_id = b.oracle_id
2687 AND a.owner = b.oracle_username;
2688
2689 EXCEPTION
2693 ||'.'
2690 WHEN no_data_found THEN
2691 raise_application_error(-20000, 'Column '
2692 || tabname
2694 || colname
2695 || ' does not exist in dba_tab_columns for the given application ');
2696 WHEN OTHERS THEN
2697 raise_application_error(-20001, 'Error in reading dictionary info. for column '
2698 || tabname
2699 ||'.'
2700 || colname );
2701 END;
2702 BEGIN
2703 INSERT
2704 INTO FND_HISTOGRAM_COLS
2705 (
2706 APPLICATION_ID ,
2707 TABLE_NAME ,
2708 COLUMN_NAME ,
2709 PARTITION ,
2710 HSIZE ,
2711 CREATION_DATE ,
2712 CREATED_BY ,
2713 LAST_UPDATE_DATE,
2714 LAST_UPDATED_BY ,
2715 LAST_UPDATE_LOGIN
2716 )
2717 VALUES
2718 (
2719 appl_id ,
2720 upper(tabname) ,
2721 upper(colname) ,
2722 upper(partname),
2723 hsize ,
2724 sysdate ,
2725 1 ,
2726 sysdate ,
2727 1 ,
2728 NULL
2729 ) ;
2730
2731 EXCEPTION
2732 WHEN DUP_VAL_ON_INDEX THEN
2733 NULL;
2734 END;
2735 END;
2736 elsif upper(action) = 'DELETE' THEN
2737 BEGIN
2738 DELETE
2739 FROM FND_HISTOGRAM_COLS
2740 WHERE application_id = appl_id
2741 AND table_name = upper(tabname)
2742 AND column_name = upper(colname)
2743 AND
2744 (
2745 partition = upper(partname)
2746 OR partition IS NULL
2747 );
2748
2749 END;
2750 END IF;
2751 IF ( commit_flag = 'Y') THEN
2752 /* for remote db operation */
2753 COMMIT;
2754 END IF;
2755 END;
2756 /* LOAD_HISTOGRAM_COLS */
2757 /************************************************************************/
2758 /* Procedure: LOAD_HISTOGRAM_COLS */
2759 /* Desciption: This is for internal purpose only. For loading into */
2760 /* SEED database */
2761 /************************************************************************/
2762 PROCEDURE LOAD_HISTOGRAM_COLS_MV(action IN VARCHAR2,
2763 ownername IN VARCHAR2,
2764 tabname IN VARCHAR2,
2765 colname IN VARCHAR2,
2766 partname IN VARCHAR2 DEFAULT NULL,
2767 hsize IN NUMBER DEFAULT 254,
2768 commit_flag IN VARCHAR2 DEFAULT 'Y')
2769 IS
2770 exist_flag VARCHAR2(5) := NULL;
2771 BEGIN
2772 IF upper(action) = 'INSERT' THEN
2773 BEGIN
2774 -- Check for existence of the table first
2775 -- break out if it doesn't exist
2776 BEGIN
2777 SELECT DISTINCT('EXIST')
2778 INTO exist_flag
2779 FROM dba_tab_columns a
2780 WHERE a.table_name = upper(tabname)
2781 AND a.column_name = upper(colname)
2782 AND a.owner = upper(ownername);
2783
2784 EXCEPTION
2785 WHEN no_data_found THEN
2786 raise_application_error(-20000, 'Column '
2787 || tabname
2788 ||'.'
2789 || colname
2790 || ' does not exist in dba_tab_columns for the given owner ');
2791 WHEN OTHERS THEN
2795 || colname );
2792 raise_application_error(-20001, 'Error in reading dictionary info. for column '
2793 || tabname
2794 ||'.'
2796 END;
2797 BEGIN
2798 INSERT
2799 INTO FND_HISTOGRAM_COLS
2800 (
2801 application_id ,
2802 OWNER ,
2803 TABLE_NAME ,
2804 COLUMN_NAME ,
2805 PARTITION ,
2806 HSIZE ,
2807 CREATION_DATE ,
2808 CREATED_BY ,
2809 LAST_UPDATE_DATE,
2810 LAST_UPDATED_BY ,
2811 LAST_UPDATE_LOGIN
2812 )
2813 VALUES
2814 (
2815 -1 ,
2816 upper(ownername),
2817 upper(tabname) ,
2818 upper(colname) ,
2819 upper(partname) ,
2820 hsize ,
2821 sysdate ,
2822 1 ,
2823 sysdate ,
2824 1 ,
2825 NULL
2826 ) ;
2827
2828 EXCEPTION
2829 WHEN DUP_VAL_ON_INDEX THEN
2830 NULL;
2831 END;
2832 END;
2833 elsif upper(action) = 'DELETE' THEN
2834 BEGIN
2835 DELETE
2836 FROM FND_HISTOGRAM_COLS
2837 WHERE owner = upper(ownername)
2838 AND table_name = upper(tabname)
2839 AND column_name = upper(colname)
2840 AND
2841 (
2842 partition = upper(partname)
2843 OR partition IS NULL
2844 );
2845
2846 END;
2847 END IF;
2848 IF ( commit_flag = 'Y') THEN
2849 /* for remote db operation */
2850 COMMIT;
2851 END IF;
2852 END;
2853 /* LOAD_HISTOGRAM_COLS_MV */
2854 /************************************************************************/
2858 /* goes for index scans instead of full table scans. The idea behind */
2855 /* Procedure: LOAD_XCLUD_STATS */
2856 /* Desciption: This will artificially pump the */
2857 /* stats with some value so that the CBO */
2859 /* this is that during a gather_schema_stats the interface tables may */
2860 /* not have data and hence the stats for such tables will be of no use */
2861 /* and hence we need to pump some artificial stats for such tables. */
2862 /* Ideally a customer has to run gather_table_stats on the interface */
2863 /* tables after populating with data. This will give them accurate data.*/
2864 /* A good methodology would be gather_table_stats once for the interface*/
2865 /* table populated with good ammount of data and for all the consecutive*/
2866 /* runs use restore_table_data procedure to restore the stats. */
2867 /* The simplified algorith for calculations are: */
2868 /* BLOCKS = num_rows*1/20, */
2869 /* AVG_ROW_LENGTH = 50% of Total max row_length */
2870 /* Clustering factor = num. of blocks */
2871 /* num. of leaf blks = */
2872 /* (cardinality)/((db_block_size -overhead 200)/key_size) */
2873 /* revised to the following as per Amozes to alway prefer index scan*/
2874 /* num. of leaf blks = 100/num of table blks */
2875 /* index_level = 1 */
2876 /* Distinct keys = num of rows */
2877 /************************************************************************/
2878 PROCEDURE LOAD_XCLUD_STATS(schemaname IN VARCHAR2)
2879 IS
2880 BEGIN
2881 -- This procedure has been deprecated. Stub is being retained for now
2882 -- so that it does not break compilation in case it is still being called.
2883 NULL;
2884 END ;
2885 /* LOAD_XCLUD_STATS */
2886 /************************************************************************/
2887 /* Procedure: LOAD_XCLUD_STATS */
2888 /* Desciption: This one is for a particular INTERFACE TABLE */
2889 /************************************************************************/
2890 PROCEDURE LOAD_XCLUD_STATS(schemaname IN VARCHAR2,
2891 tablename IN VARCHAR2)
2892 IS
2893 BEGIN
2894 -- This procedure has been deprecated. Stub is being retained for now
2895 -- so that it does not break compilation in case it is still being called.
2896 NULL;
2897 END ;
2898 /* LOAD_XCLUD_STATS */
2899 /************************************************************************/
2900 /* Procedure: CHECK_HISTOGRAM_COLS */
2901 /* Desciption: For a given list of comma seperated tables, */
2902 /* this procedure checks the */
2903 /* data in all the leading columns of all the non-unique indexes of */
2904 /* those tables and figures out if histogram needs to be created for */
2905 /* those columns. The algorithm is as follows : */
2906 /* select decode(floor(sum(tot)/(max(cnt)*75)),0,'YES','NO') HIST */
2907 /* from (select count(col) cnt , count(*) tot */
2908 /* from tab sample (S) */
2909 /* where col is not null */
2910 /* group by col); */
2911 /* The decode says whether or not a single value occupies 1/75th or */
2912 /* more of the sample. */
2913 /* If sum(cnt) is very small (a small non-null sample), the results */
2914 /* may be inaccurate. A count(*) of atleast 3000 is recommended . */
2915 /************************************************************************/
2916 PROCEDURE CHECK_HISTOGRAM_COLS(tablelist IN VARCHAR2,
2917 factor IN INTEGER,
2918 percent IN NUMBER,
2919 degree IN NUMBER DEFAULT NULL)
2920 IS
2921 BEGIN
2922 DECLARE
2923 CURSOR column_cur(tname VARCHAR2)
2924 IS
2925 SELECT DISTINCT column_name col ,
2926 b.table_name tab,
2927 b.table_owner own
2928 FROM dba_ind_columns a,
2929 dba_indexes b
2930 WHERE b.table_owner = upper(SUBSTR(tname,1,instr(tname,'.')-1))
2931 AND
2932 (
2933 b.table_name = upper(SUBSTR(tname,instr(tname,'.')+1))
2934 OR b.table_name LIKE upper(SUBSTR(tname,instr(tname,'.')+1))
2935 )
2936 AND b.uniqueness = 'NONUNIQUE'
2937 AND b.index_type = 'NORMAL'
2938 AND a.index_owner = b.owner
2939 AND a.index_name = b.index_name
2940 AND a.column_position = 1
2941 ORDER BY 3 ,
2942 2 ,
2943 1 ;
2944
2945 TYPE List
2946 IS
2947 TABLE OF VARCHAR2(62) INDEX BY BINARY_INTEGER;
2948 Table_List List;
2949 MAX_NOF_TABLES NUMBER := 32768;
2950 table_counter INTEGER := 0 ;
2951 sql_string VARCHAR2(2000);
2952 mytablelist VARCHAR2(4000);
2953 hist VARCHAR2(3);
2954 abs_tablename VARCHAR2(61);
2955 total_cnt INTEGER;
2956 max_cnt INTEGER;
2957 BEGIN
2958 -- initialize Table_list
2959 Table_List(0) := NULL;
2960 mytablelist := REPLACE(tablelist,' ','');
2961 IF (percent < 0 OR percent > 100) THEN
2962 raise_application_error(-20001,'percent must be between 0 and 100');
2963 END IF;
2964 dbms_output.put_line('Table-Name Column-Name Histogram Tot-Count Max-Count');
2965 dbms_output.put_line('==========================================================================================================');
2966 WHILE (instr(mytablelist,',') > 0)
2967 LOOP
2968 Table_List(table_counter) := SUBSTR(mytablelist,1,instr(mytablelist,',') - 1) ;
2969 Table_List(table_counter+1) := NULL;
2970 table_counter := table_counter + 1;
2971 mytablelist := SUBSTR(mytablelist,instr(mytablelist,',')+1) ;
2972 EXIT
2973 WHEN table_counter = MAX_NOF_TABLES;
2974 END LOOP;
2975 -- This gets the last table_name in a comma separated list
2976 Table_List(table_counter) := mytablelist ;
2977 Table_List(table_counter+1) := NULL;
2978 FOR i IN 0..MAX_NOF_TABLES
2979 LOOP
2980 EXIT
2981 WHEN Table_List(i) IS NULL;
2982 FOR c_rec IN column_cur(Table_List(i))
2983 LOOP
2984 --Build up the dynamic sql
2985 sql_string := 'select ';
2986 sql_string := sql_string
2987 || '/*+ PARALLEL (tab,';
2988 sql_string := sql_string
2989 || degree
2990 || ') */';
2991 sql_string := sql_string
2992 || ' decode(floor(sum(tot)/(max(cnt)*'
2993 ||factor
2994 ||')),0,''YES'',''NO'') , nvl(sum(tot),0), nvl(max(cnt),0) ';
2995 sql_string := sql_string
2996 || ' from (select count('
2997 ||c_rec.col
2998 ||') cnt, count(*) tot from ';
2999 sql_string := sql_string
3000 || c_rec.own
3001 ||'.'
3002 ||c_rec.tab
3003 || ' sample (';
3004 sql_string := sql_string
3005 || percent
3006 ||') tab ';
3007 sql_string := sql_string
3008 || ' group by '
3009 ||c_rec.col
3010 ||' )' ;
3011 BEGIN
3012 EXECUTE IMMEDIATE sql_string INTO hist,total_cnt,max_cnt;
3013 EXCEPTION
3014 WHEN zero_divide THEN
3015 hist := 'NO';
3016 END;
3017 abs_tablename := c_rec.own
3018 ||'.'
3019 ||c_rec.tab;
3020 dbms_output.put_line(rpad(upper(abs_tablename),40,' ')
3021 ||rpad(c_rec.col,30,' ')
3022 || rpad(hist,10,' ')
3023 ||lpad(TO_CHAR(total_cnt),9,' ')
3024 ||lpad(TO_CHAR(max_cnt),9,' '));
3025 END LOOP;
3026 END LOOP;
3027 END;
3028 END ;
3029 /* end of CHECK_HISTOGRAM_COLS */
3030 /************************************************************************/
3031 /* Procedure: ANALYZE_ALL_COLUMNS */
3035 PROCEDURE ANALYZE_ALL_COLUMNS(ownname IN VARCHAR2,
3032 /* Desciption: This is to create histograms on all leading cols of */
3033 /* non-unique indexes of all the tables in a given schema */
3034 /************************************************************************/
3036 percent IN NUMBER,
3037 hsize IN NUMBER,
3038 hmode IN VARCHAR2 DEFAULT 'LASTRUN' )
3039 IS
3040 BEGIN
3041 -- This procedure has been deprecated. Stub is being retained for now
3042 -- so that it does not break compilation in case it is still being called.
3043 NULL;
3044 END;
3045 /*end of ANALYZE_ALL_COLUMNS*/
3046 /************************************************************************/
3047 /* Procedure: ANALYZE_ALL_COLUMNS */
3048 /* Desciption: conc. job version of ANALYZE_ALL_COLUMNS */
3049 /************************************************************************/
3050 PROCEDURE ANALYZE_ALL_COLUMNS(errbuf OUT NOCOPY VARCHAR2,
3051 retcode OUT NOCOPY VARCHAR2,
3052 ownname IN VARCHAR2,
3053 percent IN NUMBER ,
3054 hsize IN NUMBER ,
3055 hmode IN VARCHAR2 DEFAULT 'LASTRUN' )
3056 IS
3057 BEGIN
3058 -- This procedure has been deprecated. Stub is being retained for now
3059 -- so that it does not break compilation in case it is still being called.
3060 NULL;
3061 END;
3062 /* end of ANALYZE_ALL_COLUMNS */
3063 /************************************************************************/
3064 /* Procedure: UPDATE_HIST */
3065 /* Desciption: Internal procedure to insert or update entries in table */
3066 /* fnd_stats_hist. These values are used later if restartability is */
3067 /* needed. */
3068 /************************************************************************/
3069 PROCEDURE UPDATE_HIST(schemaname VARCHAR2,
3070 objectname IN VARCHAR2,
3071 objecttype IN VARCHAR2,
3072 partname IN VARCHAR2,
3073 columntablename IN VARCHAR2,
3074 degree IN NUMBER,
3075 upd_ins_flag IN VARCHAR2,
3076 percent IN NUMBER)
3077 IS
3078 PRAGMA AUTONOMOUS_TRANSACTION ;
3079 cascade_true VARCHAR2(1);
3080 unique_constraint_detected EXCEPTION;
3081 PRAGMA EXCEPTION_INIT(unique_constraint_detected , -00001);
3082 BEGIN
3083 -- if request_id is null then we cannot do it in FULL mode, defaults to LASTRUN
3084 --- if(stathist='FULL') then
3085 --- stathist:='LASTRUN';
3086 --- end if;
3087 IF(stathist = 'LASTRUN') THEN -- retaining the old behavior as default
3088 -- S (Start) is when the entry is already in fnd_stats_hist and statistics
3089 -- were gathering is going to start for that particular object
3090 IF (upd_ins_flag = 'S') THEN
3091 UPDATE FND_STATS_HIST
3092 SET parallel = degree ,
3093 request_id = cur_request_id,
3094 request_type = request_from ,
3095 last_gather_start_time = sysdate ,
3096 last_gather_date = '' ,
3097 last_gather_end_time = '' ,
3098 est_percent =percent
3099 WHERE schema_name = upper(schemaname)
3100 AND object_name = upper(objectname)
3101 AND
3102 (
3103 partition = upper(partname)
3104 OR partname IS NULL
3105 )
3106 AND
3107 (
3108 column_table_name = upper(columntablename)
3109 OR columntablename IS NULL
3110 )
3111 AND object_type = upper(objecttype)
3112 -- and request_id=cur_request_id -- commented this line for the bug 5648754
3113 AND history_mode='L';
3114 /* Added by mo, this segment checks if an entry was updated or not.
3115 If not, a new entry will be added. */
3116 IF SQL%ROWCOUNT = 0 THEN
3117 INSERT
3118 INTO FND_STATS_HIST
3119 (
3120 SCHEMA_NAME ,
3121 OBJECT_NAME ,
3122 OBJECT_TYPE ,
3123 PARTITION ,
3124 COLUMN_TABLE_NAME ,
3125 LAST_GATHER_DATE ,
3126 LAST_GATHER_START_TIME,
3127 LAST_GATHER_END_TIME ,
3128 PARALLEL ,
3129 REQUEST_ID ,
3130 REQUEST_type ,
3131 HISTORY_MODE ,
3132 EST_PERCENT
3133 )
3137 upper(objectname),
3134 VALUES
3135 (
3136 upper(schemaname),
3138 upper(objecttype),
3139 upper(partname) ,
3140 columntablename ,
3141 '' ,
3142 sysdate ,
3143 '' ,
3144 degree ,
3145 cur_request_id ,
3146 request_from ,
3147 'L' ,
3148 percent
3149 );
3150 END IF;
3151 END IF;
3152 -- E (End) is when the entry is already in fnd_stats_hist and statistics
3153 -- gathering finished successfully for that particular object
3154 IF (upd_ins_flag = 'E') THEN
3155 UPDATE FND_STATS_HIST
3156 SET last_gather_date = sysdate,
3157 last_gather_end_time = sysdate
3158 WHERE schema_name = upper(schemaname)
3159 AND object_name = upper(objectname)
3160 AND
3161 (
3162 partition = upper(partname)
3163 OR partname IS NULL
3164 )
3165 AND
3166 (
3167 column_table_name = upper(columntablename)
3168 OR columntablename IS NULL
3169 )
3170 AND object_type = upper(objecttype)
3171 AND request_id =cur_request_id
3172 AND history_mode='L';
3173 END IF;
3174 elsif (stathist = 'FULL') THEN -- new option, old hist will not be updated
3175 IF (upd_ins_flag = 'S') THEN
3176 UPDATE FND_STATS_HIST
3177 SET parallel = degree ,
3178 request_id = cur_request_id,
3179 request_type = request_from ,
3180 last_gather_start_time = sysdate ,
3181 last_gather_date = '' ,
3182 last_gather_end_time = '' ,
3183 est_percent =percent
3184 WHERE schema_name = upper(schemaname)
3185 AND object_name = upper(objectname)
3186 AND
3187 (
3188 partition = upper(partname)
3189 OR partname IS NULL
3190 )
3191 AND
3192 (
3193 column_table_name = upper(columntablename)
3194 OR columntablename IS NULL
3195 )
3196 AND object_type = upper(objecttype)
3197 AND history_mode='F' -- F for FULL mode
3198 AND request_id =cur_request_id;
3199
3200 -- commenting out because it is not part of unique cons criteria
3201 -- and request_type=request_from;
3202 /* This segment checks if an entry was updated or not. This is still required even for
3203 FULL mode, because multiple calls for the same object from the same session will have
3204 the same cur_request_id. If not, a new entry will be added. */
3205 IF SQL%ROWCOUNT = 0 THEN
3206 INSERT
3207 INTO FND_STATS_HIST
3208 (
3209 SCHEMA_NAME ,
3210 OBJECT_NAME ,
3211 OBJECT_TYPE ,
3212 PARTITION ,
3213 COLUMN_TABLE_NAME ,
3214 LAST_GATHER_DATE ,
3215 LAST_GATHER_START_TIME,
3216 LAST_GATHER_END_TIME ,
3217 PARALLEL ,
3218 REQUEST_ID ,
3219 REQUEST_type ,
3220 HISTORY_MODE ,
3221 EST_PERCENT
3222 )
3223 VALUES
3224 (
3225 upper(schemaname),
3226 upper(objectname),
3227 upper(objecttype),
3228 upper(partname) ,
3229 columntablename ,
3230 '' ,
3231 sysdate ,
3232 '' ,
3233 degree ,
3234 cur_request_id ,
3235 request_from ,
3236 'F' ,
3237 percent
3238 );
3239
3240 END IF;
3241 END IF;
3242 -- E (End) is when the entry is already in fnd_stats_hist and statistics
3243 -- gathering finished successfully for that particular object
3244 IF (upd_ins_flag = 'E') THEN
3245 UPDATE FND_STATS_HIST
3246 SET last_gather_date = sysdate,
3247 last_gather_end_time = sysdate
3248 WHERE schema_name = upper(schemaname)
3249 AND object_name = upper(objectname)
3250 AND
3251 (
3252 partition = upper(partname)
3253 OR partname IS NULL
3254 )
3255 AND
3256 (
3257 column_table_name = upper(columntablename)
3258 OR columntablename IS NULL
3259 )
3260 AND object_type = upper(objecttype)
3261 AND history_mode='F'
3262 AND request_id =cur_request_id;
3263
3264 -- commenting out because it is not part of unique cons criteria
3265 -- and request_type=request_from;
3266 END IF;
3267 END IF;
3268 COMMIT;
3269 EXCEPTION
3270 when unique_constraint_detected then
3271 delete from fnd_stats_hist where object_name like upper(objectname) and schema_name like upper(schemaname);
3272 commit;
3273 END;
3274 /* end of UPDATE_HIST */
3275 /************************************************************************/
3276 /* Procedure: PURGE_STAT_HISTORY */
3277 /* Desciption: Purges the fnd_stat_hist table based on the FROM_REQ_ID */
3278 /* and TO_REQ_ID provided. */
3279 /************************************************************************/
3280 PROCEDURE PURGE_STAT_HISTORY(from_req_id IN NUMBER,
3284 BEGIN
3281 to_req_id IN NUMBER)
3282 IS
3283 PRAGMA AUTONOMOUS_TRANSACTION;
3285 DELETE
3286 FROM fnd_stats_hist
3287 WHERE request_id BETWEEN from_req_id AND to_req_id;
3288
3289 COMMIT;
3290 END;
3291 /************************************************************************/
3292 /* Procedure: PURGE_STAT_HISTORY */
3293 /* Desciption: Purges the fnd_stat_hist table based on the FROM_DATE */
3294 /* and TO_DATE provided. Date should be provided in DD-MM-YY format */
3295 /************************************************************************/
3296 PROCEDURE PURGE_STAT_HISTORY(purge_from_date IN VARCHAR2,
3297 purge_to_date IN VARCHAR2)
3298 IS
3299 PRAGMA AUTONOMOUS_TRANSACTION;
3300 purge_from_date_l VARCHAR2(15);
3301 purge_to_date_l VARCHAR2(15);
3302 BEGIN
3303 -- If from_date is null then from_date is sysdate-One year
3304 IF (purge_from_date IS NULL ) THEN
3305 purge_from_date_l:=TO_CHAR(sysdate-365,'DD-MM-YY');
3306 ELSE
3307 purge_from_date_l:=purge_from_date;
3308 END IF;
3309 -- If to_date is null then to_date is sysdate-One week
3310 IF (purge_to_date IS NULL ) THEN
3311 purge_to_date_l:=TO_CHAR(sysdate-7,'DD-MM-YY');
3312 ELSE
3313 purge_to_date_l:=purge_to_date;
3314 END IF;
3315 DELETE
3316 FROM fnd_stats_hist
3317 WHERE last_gather_date BETWEEN to_date(purge_from_date_l,'DD-MM-YY') AND to_date(purge_to_date_l,'DD-MM-YY');
3318
3319 COMMIT;
3320 END;
3321 /**************************************************************************/
3322 /* Procedure: PURGE_STAT_HISTORY Conc Program version */
3323 /* Desciption: Purges the fnd_stat_hist table based on the Mode parameter.*/
3324 /**************************************************************************/
3325 PROCEDURE PURGE_STAT_HISTORY(errbuf OUT NOCOPY VARCHAR2,
3326 retcode OUT NOCOPY VARCHAR2,
3327 purge_mode IN VARCHAR2,
3328 from_value IN VARCHAR2,
3329 to_value IN VARCHAR2 )
3330 IS
3331 BEGIN
3332 IF upper(purge_mode) = 'DATE' THEN
3333 PURGE_STAT_HISTORY(from_value,to_value);
3334 elsif upper(purge_mode)='REQUEST' THEN
3335 PURGE_STAT_HISTORY(to_number(from_value),to_number(to_value));
3336 END IF;
3337 EXCEPTION
3338 WHEN OTHERS THEN
3339 errbuf := sqlerrm ;
3340 retcode := '2';
3341 FND_FILE.put_line(FND_FILE.log,errbuf);
3342 raise;
3343 END;
3344 /************************************************************************/
3345 /* Procedure: table_stats */
3346 /* Desciption: Internal procedures used by verify_stats. Gets info about*/
3347 /* table stats. */
3348 /************************************************************************/
3349 PROCEDURE table_stats(schema VARCHAR2,
3350 tableName VARCHAR2)
3351 IS
3352 last_analyzed dba_tables.last_analyzed%type;
3353 sample_size dba_tables.sample_size%type;
3354 num_rows dba_tables.num_rows%type;
3355 blocks dba_tables.blocks%type;
3356 BEGIN
3357 SELECT last_analyzed ,
3358 sample_size ,
3359 TRUNC(num_rows),
3360 blocks
3361 INTO last_analyzed,
3362 sample_size ,
3363 num_rows ,
3364 blocks
3365 FROM dba_tables
3366 WHERE table_name = tableName
3367 AND owner = schema;
3368
3369 dbms_output.put_line('===================================================================================================');
3370 dbms_output.put_line(' Table '
3371 || tableName);
3372 dbms_output.put_line('===================================================================================================');
3373 dbms_output.put_line(rpad('last analyzed', 18, ' ')
3374 || rpad('sample_size', 12, ' ')
3375 ||rpad('num_rows', 20, ' ')
3376 ||rpad('blocks', 10, ' '));
3377 dbms_output.put_line(rpad(TO_CHAR(last_analyzed, 'MM-DD-YYYY hh24:mi'), 18, ' ')
3378 || rpad(sample_size, 12, ' ')
3379 || rpad(num_rows, 20, ' ')
3380 ||blocks);
3381 dbms_output.put_line(' ');
3382 EXCEPTION
3383 WHEN no_data_found THEN
3384 dbms_output.put_line('=================================================================================================');
3385 dbms_output.put_line('Table not found; Owner: '
3386 || schema
3387 ||', name: '
3388 || tableName);
3389 dbms_output.put_line('=================================================================================================');
3390 END table_stats;
3391 /************************************************************************/
3392 /* Procedure: index_stats */
3393 /* Desciption: Internal procedures used by verify_stats. Gets info about*/
3394 /* index stats. */
3395 /************************************************************************/
3396 PROCEDURE index_stats(lowner VARCHAR2,
3397 indexName VARCHAR2)
3398 IS
3399 last_analyzed dba_indexes.last_analyzed%type;
3400 num_rows dba_indexes.num_rows%type;
3401 leaf_blocks dba_indexes.leaf_blocks%type;
3402 distinct_keys dba_indexes.distinct_keys%type;
3403 avg_leaf_blocks_per_key dba_indexes.avg_leaf_blocks_per_key%type;
3407 val1 VARCHAR2(255);
3404 avg_data_blocks_per_key dba_indexes.avg_data_blocks_per_key%type;
3405 clustering_factor dba_indexes.clustering_factor%type;
3406 uniqueness dba_indexes.uniqueness%type;
3408 val2 VARCHAR2(255);
3409 val3 VARCHAR2(255);
3410 val4 VARCHAR2(255);
3411 BEGIN
3412 SELECT last_analyzed ,
3413 TRUNC(num_rows) ,
3414 leaf_blocks ,
3415 distinct_keys ,
3416 avg_leaf_blocks_per_key,
3417 avg_data_blocks_per_key,
3418 clustering_factor ,
3419 uniqueness
3420 INTO last_analyzed ,
3421 num_rows ,
3422 leaf_blocks ,
3423 distinct_keys ,
3424 avg_leaf_blocks_per_key,
3425 avg_data_blocks_per_key,
3426 clustering_factor ,
3427 uniqueness
3428 FROM dba_indexes
3429 WHERE owner = lowner
3430 AND index_name = indexName;
3431
3432 val1:= rpad(indexname, 30, ' ')
3433 || rpad(TO_CHAR(last_analyzed, 'MM-DD-YYYY hh24:mi'), 18,' ');
3434 val2:= rpad(num_rows, 10, ' ')
3435 ||rpad(leaf_blocks, 8, ' ');
3436 val3:= rpad(distinct_keys, 9, ' ')
3437 || rpad(avg_leaf_blocks_per_key, 8, ' ');
3438 val4:= rpad(avg_data_blocks_per_key, 8, ' ')
3439 || rpad(clustering_factor, 9, ' ');
3440 dbms_output.put_line(val1
3441 || val2
3442 || val3
3443 || val4);
3444 END index_stats;
3445 /************************************************************************/
3446 /* Procedure: histo_header */
3447 /* Desciption: Internal procedures used by verify_stats. Prints header */
3448 /* for histograms in the o/p file */
3449 /************************************************************************/
3450 PROCEDURE histo_header
3451 IS
3452 BEGIN
3453 dbms_output.put_line('----------------------------------------------------------------------------------------------------');
3454 dbms_output.put_line(' Histogram Stats');
3455 dbms_output.put_line(rpad('Schema', 15, ' ')
3456 ||rpad('Table Name', 31, ' ')
3457 ||rpad('Status', 12, ' ')
3458 ||rpad('last analyzed', 18, ' ')
3459 || 'Column Name');
3460 dbms_output.put_line('----------------------------------------------------------------------------------------------------');
3461 END;
3462 /************************************************************************/
3463 /* Procedure: index_header */
3464 /* Desciption: Internal procedures used by verify_stats. Prints header */
3465 /* for indexes in the o/p file */
3466 /************************************************************************/
3467 PROCEDURE index_header
3468 IS
3469 val1 VARCHAR2(255);
3470 val2 VARCHAR2(255);
3471 val3 VARCHAR2(255);
3472 val4 VARCHAR2(255);
3473 BEGIN
3474 val1 := rpad('Index name', 30, ' ')
3475 || rpad('last analyzed', 18, ' ');
3476 val2 := rpad('num_rows', 10, ' ')
3477 || rpad('LB', 8, ' ');
3478 val3 := rpad('DK', 9, ' ')
3479 || rpad('LB/key', 8, ' ');
3480 val4 := rpad('DB/key', 8, ' ')
3481 ||rpad('CF', 9, ' ');
3482 dbms_output.put_line(val1
3483 || val2
3484 || val3
3485 || val4);
3486 dbms_output.put_line('----------------------------------------------------------------------------------------------------');
3487 END;
3488 /************************************************************************/
3489 /* Procedure: histo_stats */
3490 /* Desciption: Internal procedures used by verify_stats. Gets info about*/
3491 /* about histogram stats. */
3492 /************************************************************************/
3493 PROCEDURE histo_stats(schema VARCHAR2,
3494 tableName VARCHAR2,
3495 columnName VARCHAR2)
3496 IS
3497 found0 BOOLEAN := false;
3498 found1 BOOLEAN := false;
3499 status VARCHAR2(64) := 'not present';
3500 last_analyzed dba_tab_columns.last_analyzed%type;
3501 CURSOR histo_details(schema VARCHAR2, tableName VARCHAR2, columnName VARCHAR2)
3502 IS
3503 SELECT endpoint_number,
3504 last_analyzed
3505 FROM dba_histograms a,
3506 dba_tab_columns b
3507 WHERE a.owner = schema
3508 AND a.table_name = tableName
3509 AND a.column_name = columnName
3510 AND a.owner = b.owner
3511 AND a.table_name = b.table_name
3512 AND a.column_name = b.column_name
3513 AND endpoint_number NOT IN (0,
3514 1);
3515
3516 BEGIN
3517 FOR each_histo IN histo_details(schema, tableName, columnName)
3518 LOOP
3519 last_analyzed := each_histo.last_analyzed;
3520 status := 'present';
3521 EXIT;
3522 END LOOP;
3523 dbms_output.put_line(rpad(schema, 15, ' ')
3524 || rpad(tableName, 31, ' ')
3525 || rpad(status, 12, ' ')
3526 || rpad(TO_CHAR(last_analyzed, 'DD-MM-YYYY hh24:mi'), 18, ' ')
3527 || columnName);
3528 EXCEPTION
3529 WHEN no_data_found THEN
3533 ||', name: '
3530 dbms_output.put_line('=================================================================================================');
3531 dbms_output.put_line('Histogram not found; Owner: '
3532 || schema
3534 || tableName
3535 || ', column name: '
3536 || columnName);
3537 dbms_output.put_line('=================================================================================================');
3538 END histo_stats;
3539 /************************************************************************/
3540 /* Procedure: file_tail */
3541 /* Desciption: Internal procedures used by verify_stats. Prints legend */
3542 /* in the o/p file */
3543 /************************************************************************/
3544 PROCEDURE file_tail
3545 IS
3546 BEGIN
3547 dbms_output.put_line(' ');
3548 dbms_output.put_line(' ');
3549 dbms_output.put_line('Legend:');
3550 dbms_output.put_line('LB : Leaf Blocks');
3551 dbms_output.put_line('DK : Distinct Keys');
3552 dbms_output.put_line('DB : Data Blocks');
3553 dbms_output.put_line('CF : Clustering Factor');
3554 END;
3555 /************************************************************************/
3556 /* Procedure: column_stats */
3557 /* Desciption: Internal procedures used by verify_stats. Gets info about*/
3558 /* about column stats. */
3559 /************************************************************************/
3560 PROCEDURE column_stats(column_name dba_tab_columns.column_name%type,
3561 num_distinct dba_tab_columns.num_distinct%type,
3562 num_nulls dba_tab_columns.num_nulls%type,
3563 density dba_tab_columns.density%type,
3564 sample_size dba_tab_columns.sample_size%type,
3565 last_analyzed dba_tab_columns.last_analyzed%type,
3566 first_col BOOLEAN)
3567 IS
3568 val1 VARCHAR2(255);
3569 val2 VARCHAR2(255);
3570 val3 VARCHAR2(255);
3571 BEGIN
3572 IF (first_col = true) THEN
3573 dbms_output.put_line('----------------------------------------------------------------------------------------------------');
3574 dbms_output.put_line(' Column Stats');
3575 val1 := rpad('Column name', 31, ' ')
3576 || rpad('sample_size', 12, ' ');
3577 val2 := rpad('num_distinct', 14, ' ')
3578 || rpad('num_nulls', 14, ' ');
3579 val3 := rpad('density', 12, ' ')
3580 || rpad('last analyzed', 18, ' ');
3581 dbms_output.put_line(val1
3582 ||val2
3583 ||val3);
3584 dbms_output.put_line('----------------------------------------------------------------------------------------------------');
3585 END IF;
3586 val1 := rpad(column_name, 31, ' ')
3587 || rpad(sample_size, 12, ' ');
3588 val2 := rpad(num_distinct, 14, ' ')
3589 || rpad(TRUNC(num_nulls), 14, ' ');
3590 val3 := rpad(TRUNC(density, 9), 12, ' ')
3591 || rpad(TO_CHAR(last_analyzed, 'MM-DD-YYYY hh24:mi'), 18, ' ');
3592 dbms_output.put_line(val1
3593 || val2
3594 || val3);
3595 END;
3596 /************************************************************************/
3597 /* Procedure: verify_stats */
3598 /* Desciption: Checks stats for database objects depending on input. */
3599 /* Sends its output to the screen. Should be called from SQL prompt, and*/
3600 /* o/p should be spooled to a file. Can be used to check all tables in */
3601 /* schema, or particular tables. Column stats can also be checked. */
3602 /************************************************************************/
3603 PROCEDURE verify_stats(schemaName VARCHAR2 DEFAULT NULL,
3604 tableList VARCHAR2 DEFAULT NULL,
3605 days_old NUMBER DEFAULT NULL,
3606 column_stat BOOLEAN DEFAULT false)
3607 IS
3608 CURSOR all_tables(schema VARCHAR2)
3609 IS
3610 SELECT table_name,
3611 owner
3612 FROM dba_tables dt
3613 WHERE owner = schema
3614 AND
3615 (
3616 iot_type <> 'IOT_OVERFLOW'
3617 OR iot_type IS NULL
3618 )
3619 AND
3620 (
3621 (
3622 sysdate - NVL(last_analyzed, to_date('01-01-1900', 'MM-DD-YYYY'))
3623 )
3624 >days_old
3625 OR days_old IS NULL
3626 )
3627 ORDER BY table_name;
3628
3629 CURSOR all_indexes(schema VARCHAR2, tableName VARCHAR2)
3630 IS
3631 SELECT index_name,
3632 owner
3633 FROM dba_indexes
3634 WHERE table_owner = schema
3635 AND table_name = tableName
3636 ORDER BY index_name;
3637
3638 /*cursor all_histograms(schema varchar2, tableName varchar2) is
3639 select a.column_name
3640 from fnd_histogram_cols a,
3641 fnd_oracle_userid b,
3642 fnd_product_installations c
3643 where a.application_id = c.application_id
3644 and c.oracle_id = b.oracle_id
3645 and b.oracle_username = schema
3646 and a.table_name = tableName
3647 order by a.column_name;*/
3651 FROM fnd_histogram_cols a
3648 CURSOR all_histograms(schema VARCHAR2, tableName VARCHAR2)
3649 IS
3650 SELECT a.column_name
3652 WHERE a.table_name = tableName
3653 ORDER BY a.column_name;
3654
3655 CURSOR all_columns(schema VARCHAR2, tableName VARCHAR2)
3656 IS
3657 SELECT COLUMN_NAME ,
3658 NUM_DISTINCT,
3659 NUM_NULLS ,
3660 DENSITY ,
3661 SAMPLE_SIZE ,
3662 LAST_ANALYZED
3663 FROM dba_tab_columns
3664 WHERE owner = schema
3665 AND table_name = tableName
3666 ORDER BY column_name;
3667
3668 MyTableList VARCHAR2(4000);
3669 MySchema VARCHAR2(255);
3670 TYPE List
3671 IS
3672 TABLE OF VARCHAR2(64) INDEX BY BINARY_INTEGER;
3673 Table_Name List;
3674 Table_Owner List;
3675 table_counter INTEGER := 1;
3676 MAX_NOF_TABLES NUMBER := 32768;
3677 operation VARCHAR2(64):= '';
3678 ownerIndex NUMBER(1);
3679 first_histo BOOLEAN;
3680 first_index BOOLEAN;
3681 first_col BOOLEAN;
3682 verify_stats_exception EXCEPTION;
3683 BEGIN
3684 dbms_output.enable(1000000);
3685 -- read all input params into plsql vars
3686 MySchema := upper(schemaName);
3687 MyTableList := REPLACE(upper(TableList), ' ', '');
3688 -- clean up input data
3689 -- start with the tables list
3690 IF MyTableList IS NULL THEN
3691 -- user wants to inspect all tables in schema
3692 IF MySchema IS NOT NULL THEN
3693 operation := 'schema';
3694 END IF;
3695 ELSE
3696 operation := 'table';
3697 END IF;
3698 Table_Name(1) := NULL;
3699 Table_Owner(1) := NULL;
3700 -- check operation flag and process accordingly
3701 IF operation = 'table' THEN
3702 -- initialize Table_list
3703 WHILE (instr(MyTableList,',') > 0)
3704 LOOP
3705 dbms_output.put_line('MyTableList '
3706 || mytableList);
3707 Table_Name(table_counter) := SUBSTR(mytablelist,1,instr(mytablelist,',') - 1) ;
3708 ownerIndex := instr(Table_Name(table_counter), '.');
3709 IF ownerIndex <> 0 THEN
3710 Table_Owner(table_counter):= SUBSTR(Table_Name(table_counter), 1, ownerIndex-1);
3711 Table_Name(table_counter) := SUBSTR(Table_Name(table_counter), ownerIndex+1);
3712 ELSE
3713 Table_Owner(table_counter):= MySchema;
3714 END IF;
3715 table_counter := table_counter + 1;
3716 Table_Name(table_counter) := NULL;
3717 Table_Owner(table_counter) := NULL;
3718 MyTableList := SUBSTR(MyTableList,instr(MyTableList,',')+1) ;
3719 EXIT
3720 WHEN table_counter = MAX_NOF_TABLES;
3721 END LOOP;
3722 -- This gets the last table_name in a comma separated list
3723 Table_Name(table_counter) := MyTableList ;
3724 -- check if owner is specified on command line or not
3725 OwnerIndex := instr(Table_Name(table_counter), '.');
3726 IF ownerIndex <> 0 THEN
3727 Table_Owner(table_counter):= SUBSTR(Table_Name(table_counter), 1, ownerIndex-1);
3728 Table_Name(table_counter) := SUBSTR(Table_Name(table_counter), ownerIndex+1);
3729 ELSE
3730 Table_Owner(table_counter):= MySchema;
3731 END IF;
3732 Table_Name(table_counter+1) := NULL;
3733 Table_Owner(table_counter+1) := NULL;
3734 elsif operation = 'schema' THEN
3735 -- retrieve all tables for schema and continue with processing
3736 OPEN all_tables(MySchema);
3737 FETCH all_tables BULK COLLECT
3738 INTO Table_Name,
3739 Table_Owner LIMIT MAX_NOF_TABLES;
3740
3741 CLOSE all_tables;
3742 ELSE -- error occurred
3743 raise verify_stats_exception;
3744 END IF;
3745 -- loop all the tables and check their stats and indexes
3746 FOR i IN 1..Table_Name.last
3747 LOOP
3748 EXIT
3749 WHEN Table_Name(i) IS NULL;
3750 first_histo := true;
3751 first_index := true;
3752 first_col := true;
3753 -- get table stats first
3754 table_stats(Table_Owner(i), Table_Name(i));
3755 -- do the stats for all table columns if flag is yes
3756 IF (column_stat = true) THEN
3757 FOR col_rec IN all_columns(Table_Owner(i), Table_Name(i))
3758 LOOP
3759 column_stats(col_rec.column_name, col_rec.num_distinct, col_rec.num_nulls, col_rec.density, col_rec.sample_size, col_rec.last_analyzed, first_col);
3760 first_col:= false;
3761 END LOOP;
3762 END IF;
3763 -- do the stats for all table indexes
3764 FOR index_rec IN all_indexes(Table_Owner(i), Table_Name(i))
3765 LOOP
3766 IF first_index = true THEN
3767 index_header();
3768 first_index := false;
3769 END IF;
3770 index_stats(index_rec.owner, index_rec.index_Name);
3771 END LOOP;
3772 -- do the stats for all table histograms
3773 FOR histo_rec IN all_histograms(Table_Owner(i), Table_Name(i))
3774 LOOP
3775 IF first_histo = true THEN
3776 histo_header();
3777 first_histo:= false;
3778 END IF;
3779 histo_stats(Table_Owner(i), Table_Name(i), histo_rec.column_name);
3780 END LOOP;
3781 END LOOP;
3782 file_tail();
3783 EXCEPTION
3784 WHEN verify_stats_exception THEN
3785 dbms_output.put_line('verify_stats(schema_name varchar2 default null,
3786 table_list varchar2 default null, days_old number default null,
3787 column_stats boolean defualt false)');
3788 END ;
3789 /* end of verify_stats*/
3790 BEGIN
3791 -- Get the default DOP that will be used if none is provided.
3792 GET_PARALLEL(def_degree);
3793 dummybool := fnd_installation.get_app_info('FND',dummy1,dummy2,fnd_statown);
3794 -- select substr(version,1,instr(version,'.')-1)
3795 SELECT REPLACE(SUBSTR(version,1,instr(version,'.',1,2)-1),'.')
3796 INTO db_versn
3797 FROM v$instance;
3798
3799 -- Initialize cur_request_id
3800 cur_request_id:=GET_REQUEST_ID;
3801 -- dbms_output.put_line('Database version is '||db_versn);
3802 EXCEPTION
3803 WHEN OTHERS THEN
3804 db_versn:=81; -- Just in case, default it to 8i
3805 END FND_STATS;