MINI MINI MANI MO

Path : /opt/oracle/product/18c/dbhomeXE/rdbms/admin/
File Upload :
Current File : //opt/oracle/product/18c/dbhomeXE/rdbms/admin/perfhubrpt.sql

Rem
Rem $Header: rdbms/admin/perfhubrpt.sql /main/5 2017/05/28 22:46:08 stanaya Exp $
Rem
Rem perfrpt.sql
Rem
Rem Copyright (c) 2013, 2017, Oracle and/or its affiliates. 
Rem All rights reserved.
Rem
Rem    NAME
Rem      perfhubrpt.sql
Rem
Rem    DESCRIPTION
Rem      This is the script to generate perfhub active report.
Rem      User can generate perfhub report for the following cases:
Rem           a. From pdb:
Rem               1. For pdb, using awr_pdb_xxxx views
Rem                   -- uses pdb's con_dbid
Rem               2. For imported data, using awr_pdb_xxx views
Rem               3. For pdb, using awr_root_xxxx views
Rem                   -- uses ROOT's dbid
Rem           b. From Root:
Rem               1. For ROOT and  imported data 
Rem                     using awr_root_xxxs views
Rem               2. For PDB, using awr_root_xxxx views
Rem           c. From Non_CDB, using awr_root_xxxx views
Rem
Rem    NOTES
Rem      <other useful comments, qualifications, etc.>
Rem
Rem    BEGIN SQL_FILE_METADATA
Rem    SQL_SOURCE_FILE: rdbms/admin/perfhubrpt.sql
Rem    SQL_SHIPPED_FILE: rdbms/admin/perfhubrpt.sql
Rem    SQL_PHASE: UTILITY
Rem    SQL_STARTUP_MODE: NORMAL
Rem    SQL_IGNORABLE_ERRORS: NONE
Rem    END SQL_FILE_METADATA
Rem    
Rem    MODIFIED   (MM/DD/YY)
Rem    zhcai       08/22/16 - non cdb fix
Rem    yxie        08/17/16 - always generate hist report for imported data
Rem    sshastry    05/23/16 - Generate pdb perfhub report
Rem    jinhuo      06/23/14 - Make script more robust
Rem    jinhuo      02/12/14 - Improve time period selection
Rem    jinhuo      12/10/13 - Creation


set timing off veri off space 1 flush on pause off termout on numwidth 10;
set echo off feedback off pagesize 60 linesize 80 newpage 1 recsep off;
set trimspool on trimout on define "&" concat "." serveroutput on;

-- set date format
var date_fmt                 varchar2(32)
-- declare default start end time variables
var v_default_start          varchar2(19);
var v_default_end            varchar2(19);
var v_outer_interval         number;
var v_selected_interval      number;
-- msg to display
var msg varchar2(32767);
var is_root_selected         number;
begin
-- date format
:date_fmt := 'mm/dd/yyyy hh24:mi:ss';
end;
/

prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prompt ~                   PERFHUB ACTIVE REPORT                              ~
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prompt ~  This script will generate PerfHub active report according to        ~
prompt ~  users input.  The script will prompt users for the                  ~
prompt ~  following information:                                              ~
prompt ~     (1) report level: basic, typical or all                          ~
prompt ~     (2) dbid                                                         ~
prompt ~     (3) instance id                                                  ~
prompt ~     (4) selected time range                                          ~
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- prompt for report level
prompt 
prompt Specify the report level
prompt ~~~~~~~~~~~~~~~~~~~~~~~~
prompt *  Please enter basic, typical or all                     
prompt *  Report level "basic" - include tab contents but no further details
prompt *  Report level "typical" - include tab contents with details for top
prompt *                           SQL statements
prompt *  Report level "all" - include tab contents with details for all SQL
prompt *                       statements
prompt                      
accept report_level prompt "Please enter report level [typical]: "
prompt

set heading off;
var v_rpt_level varchar2(10);
begin
  select 'Using ' || rpt_level || ' for report level',
         rpt_level
  into :msg, :v_rpt_level
  from
    (select
         case lower(nvl('&&report_level' , 'typical'))
           when 'basic' then 'basic'
           when 'all'  then 'all'
           else 'typical'
         end rpt_level
     from sys.dual) t;
end;
/
print :msg;
set heading on;


-- get current database id and instance number
set termout off;
column db_inst_num  heading "Inst Num"  new_value db_inst_num  format 99999 noprint;
column db_inst_name heading "Instance"  new_value db_inst_name format a12 noprint;
column db_db_name   heading "DB Name"   new_value db_db_name   format a12 noprint;
column db_dbid      heading "DB Id"     new_value db_dbid noprint;

select d.dbid            db_dbid
     , d.name            db_db_name
     , i.instance_number db_inst_num
     , i.instance_name   db_inst_name
  from v$database d,
       v$instance i;
set termout on;

-- list databases and instances
set underline on;
column DBID        heading "DB Id"              format a12;
column a_db_name   heading "DB Name"            format a12;
column a_cont_name heading "AWR Data Source"    format a24;
column type        heading "Type"               format a24;

prompt
prompt
prompt Available Databases and Instances. 
prompt The database with * is current database
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

select distinct 
      (case 
          when a.a_dbid = sys_context('userenv','con_dbid') THEN '* '
          else '  ' 
       end) || a.a_dbid DBID, 
       a.a_db_name, a.a_cont_name, 
      (case    data_source_type
        when 'ROOT' THEN 
          case rac
            when 'YES' THEN 
              case cdb 
                when 'YES' THEN 'CDB, RAC'
                else 'NON_CDB, RAC'
              end   
            else 
              case cdb 
                when 'YES' THEN 'CDB'
                else 'NON_CDB'
              end 
          end
        when 'PDB' THEN 
          case rac
            when 'YES' THEN 'PDB, RAC'
            else 'PDB'
          end  
        when 'IMPORTED' THEN
          case rac
            when 'YES' THEN 
              case cdb
                when 'YES' THEN 
                  case 
                    when (sys.dbms_sqltune_util2.is_imported_pdb(a.a_dbid) =  'yes')
                      then 'IMPORTED, RAC, PDB'
                    else
                      'IMPORTED, RAC, CDB'
                  end    
                else 'IMPORTED, RAC'
              end
            when 'NO' THEN
              case cdb
                when 'YES' THEN 
                  case 
                    when (sys.dbms_sqltune_util2.is_imported_pdb(a.a_dbid) =  'yes')
                      then 'IMPORTED, PDB'
                    else 'IMPORTED, CDB'
                  end  
                else 'IMPORTED' 
              end  
            else 'IMPORTED' 
          end  
      end ) type 
  from
(
  select wr.dbid a_dbid,
         wr.db_name a_db_name,
         (case wr.cdb
            when 'YES' THEN 'CDB$ROOT'
            else wr.db_name -- in non_cdb, display db_name
          end) a_cont_name,
         sys.dbms_sqltune_util2.resolve_database_type(wr.dbid) data_source_type,
         wr.parallel rac, wr.cdb cdb, wr.con_id con_id 
  from awr_root_database_instance wr
  UNION ALL
  select wr.dbid a_dbid,
           wr.db_name a_db_name,
           nvl(pi.pdb_name, wr.db_name) data_source,
           sys.dbms_sqltune_util2.resolve_database_type(wr.dbid) data_source_type,
           wr.parallel rac, wr.cdb cdb, wr.con_id con_id
  from awr_pdb_database_instance wr,
       awr_pdb_pdb_instance pi
  where wr.dbid  = pi.con_dbid (+) 
        and sys_context('userenv', 'con_id') > 2
) a ;   



prompt
prompt Specify the database ID
prompt ~~~~~~~~~~~~~~~~~~~~~~~
accept dbid prompt "Please enter database ID [&db_dbid]: " 
prompt

set heading off;
var v_dbid number;
var v_valid_dbid number;

declare 
    INVALID_DBID_EXCEPTION EXCEPTION;
begin
    :v_valid_dbid := 0;

  select 'Using ' || nvl('&&dbid', '&db_dbid') || ' for database ID'
         , to_number(nvl('&&dbid', '&db_dbid'), '9999999999')
  into :msg, :v_dbid
  from sys.dual;

     -- check whether user entered dbid is current dbid or current con_dbid
     if ( (:v_dbid = sys_context('userenv','dbid')) or 
          (:v_dbid = sys_context('userenv','con_dbid'))
        ) 
     then
        :v_valid_dbid := 1; --valid dbid
     end if;

     -- If :v_valid_dbid is still 0, then it could be imported dbid.
     -- Note: In case of imported RAC NON-CDB/CDB, value of :v_valid_dbid 
     -- could be >= 1, due to multiple rows for each instance in the view
     if (:v_valid_dbid = 0) 
     then 
         select count(*) into :v_valid_dbid from awr_pdb_database_instance 
         where dbid = :v_dbid;
     end if;

     -- If not a valid dbid, throw an exception.
     if (:v_valid_dbid = 0) then 
        RAISE INVALID_DBID_EXCEPTION;
     end if;

exception
  when others then
   select 'Invalid/No Database ID was entered. Using &db_dbid for Database ID'
       , &db_dbid
    into :msg, :v_dbid
    from sys.dual;
end;
/
print :msg;
set heading on;

var is_root_selected number;

set heading off;
declare
    v_is_root number;
begin
    if (:v_dbid = sys_context('userenv','dbid')) then
        v_is_root := 1;
    else 
        v_is_root := 0;
    end if;

    select v_is_root into :is_root_selected from dual;

end;
/

set heading on;

-- get current database id and instance number
set termout off;
column c_dbid      heading "DB Id"              new_value dbid noprint a32;
column con_name     heading "Container Name"    new_value con_name noprint;

select distinct name con_name, dbid c_dbid, con_id 
  from v$containers
  where con_id <> 2
  order by con_id desc;

set termout on;

set heading off;
select 'Please specify the container name for which to generate the report' 
from dual 
where :is_root_selected = 1 and sys_context('userenv','con_id') = 1;

select 'List of available open container(s):' 
from dual
where :is_root_selected = 1 and sys_context('userenv','con_id') = 1;

select 'Note: Upto 10 open container(s) on this instance are displayed below.
Enter a valid container name.' 
from dual
where :is_root_selected = 1 and sys_context('userenv','con_id') = 1;

set heading on;

column con_dbid   heading "Container DBID"   new_value con_dbid;
column cont_name  heading "Container Name"   new_value cont_name format a24;

select
 (case when rn < 11 then cont_name else '...' end) cont_name,
 (case when rn < 11 then con_dbid else null end) con_dbid,
 (case when rn < 11 then type else null end) type
from
(select
 (case
      when name = sys_context('userenv','con_name') THEN '* '
      else ' '
      end) || name cont_name,
    dbid con_dbid, decode (name, 'CDB$ROOT', 'CDB', 'PDB')  type, rownum rn
  from v$containers
  where
  :is_root_selected = 1 and
  con_id <> 2 and
  open_mode='READ WRITE' and
  rownum < 12 and
  sys_context('userenv','con_id') = 1);

-- accept con_name prompt "Please enter container name [&con_name]: " 
-- prompt

set echo off;
SET TERMOUT OFF
column con_name_prompt new_value con_name_prompt
column con_name new_value con_name
set define off

select case 
         when ( (:is_root_selected = 1) 
                 and (sys_context('userenv','con_id') = 1) )
            then 'Please enter container name: ' 
         else 'Generating report for selected data source. Please press Enter'
       end "con_name_prompt"  
from dual;

set define on
SET TERMOUT ON

prompt
accept con_name prompt '&&con_name_prompt'
prompt

-- -----------------------------------
set heading off;
var v_con_name varchar2(128);
var v_con_name_valid number;

declare 
    INVALID_CON_NAME_EXCEPTION EXCEPTION;
begin
    :v_con_name_valid := 1;

    if ( (:is_root_selected = 1) and (sys_context('userenv','con_id') = 1) ) 
    then
        select 'Using ' || nvl('&&con_name', 'CDB$ROOT') || 
                    ' for container name' , nvl('&&con_name', 'CDB$ROOT')
        into :msg, :v_con_name
        from sys.dual 
        where :is_root_selected = 1
        ;

        select 1 into :v_con_name_valid from sys.dual where 
        -- :is_root_selected = 1 and 
        :v_con_name in (
            select name from v$containers 
            where con_id <> 2 and open_mode='READ WRITE'
            );

         if (:v_con_name_valid = 0) then 
            RAISE INVALID_CON_NAME_EXCEPTION;
         end if;
    else 
    -- reset msg
        :msg := ''; 
    end if;

exception
 when TOO_MANY_ROWS then 
    null;
 when NO_DATA_FOUND then 
    -- null;
    select 
    'Invalid/No container name was entered. Using CDB$ROOT for container name'
       , 'CDB$ROOT'     -- nvl('&con_name', 'CDB$ROOT')
    into :msg, :v_con_name
    from sys.dual;

 when INVALID_CON_NAME_EXCEPTION then
    select 
    'Invalid/No container name was entered. Using CDB$ROOT for container name'
       , 'CDB$ROOT'     -- nvl('&con_name', 'CDB$ROOT')
    into :msg, :v_con_name
    from sys.dual;
 when others then 
    null;
end;
/

print :msg;
set heading on;

-- -----------------------------------

-- create instance prompt script file dynamically
-- No need to query dba_hist_database_instance.
-- awr_pdb_database_instance has the same data as dba_hist_database_instance 
-- in SI,ROOT,PDB case(For imported and local awr data)
var is_rac number;
begin
  select is_rac into :is_rac
  from (
    select case when parallel = 'YES'
                  then 1
                else 0
           end is_rac
    from v$instance
    where :v_dbid=&db_dbid
    union 
    select case when parallel = 'YES'
                  then 1
                else 0
           end is_rac 
    from  awr_pdb_database_instance
    where dbid=:v_dbid and :v_dbid!=&db_dbid 
  );
end;
/

set echo off;
SET TERMOUT OFF
column inst_prompt new_value inst_prompt
column inst_id new_value inst_id
set define off

select case :is_rac 
         when 1 then 'Please enter instance number [all instances]:' 
         else 'Single Instance Database. Please press Enter' 
       end "inst_prompt"  
from dual;

set define on
SET TERMOUT ON

prompt
prompt Specify the Instance Number
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
accept inst_id prompt '&&inst_prompt'
prompt

set heading off;
var v_inst_id number;
begin
  select case :is_rac 
           when 1 then 
             'Using ' || decode(lower('&&inst_id'), 
                                null, 'all instances', 
                                'null', 'all instances',                                  
                                '&&inst_id')  || ' for instance'
           else null
         end,
         case :is_rac
           when 1 then 
             to_number(
               decode(lower('&&inst_id'), 'all instances', null, 
                                  'null', null, '&&inst_id'),
               '9999999999'
             )
           else null
         end
  into :msg, :v_inst_id
  from sys.dual;
exception
  when others then
    select 
      'Invalid instance number was entered. Using "all instances" for instance'
      , null
    into :msg, :v_inst_id
    from sys.dual;
end;
/
print :msg;
set heading on;

-- default start time
column start_time heading "Default Start Time" new_value start_time format a19;
-- default end time and available end time 
-- (current time or max time in historical data)
column end_time   heading "Default End Time" new_value end_time   format a19;
-- available start time (min time in historical data)
column a_start_time heading "Oldest Available Snapshot Time" new_value a_start_time format a30;


var pdb_type number;
begin
    -- IMPORTED => imported into current container/pdb
    -- NOTE: Even at root, awr_pdb_xxxx views contains imported data
    if (sys.dbms_sqltune_util2.resolve_database_type(:v_dbid)  
         in (sys.dbms_sqltune_util2.DB_TYPE_PDB, 
             sys.dbms_sqltune_util2.DB_TYPE_IMP) ) 
    then
       :pdb_type := 2;
    else 
       :pdb_type := 0;
    end if;
end;
/


-- adjusted half seconds to snapshot end interval to cover precision lost

select a.start_time, a.end_time, a.a_start_time
    FROM
       ( select to_char(start_time, :date_fmt) start_time,
               to_char(max_time,:date_fmt) end_time,
               to_char(min_time, :date_fmt) a_start_time
        from (
          select case :v_dbid when &db_dbid then rmx.max_time
                              else mx.max_time 
                 end max_time, 
                 case :v_dbid when &db_dbid then rmx.min_time
                              else mx.min_time 
                 end min_time, 
                 case :v_dbid when &db_dbid then rmx.start_time
                      else greatest(nvl(smx.sec_max_time, mx.max_time - 1/24), 
                                            mx.min_time
                                   )
                 end start_time
          from (
            select max(end_interval_time + 1/172800) max_time,
                   min(end_interval_time - 1/172800) min_time
            from awr_pdb_snapshot    
            where dbid=:v_dbid and :v_dbid != &db_dbid
          ) mx, 
          (
            select max(end_interval_time +  1/172800) sec_max_time
            from awr_pdb_snapshot sn, (
              select snap_id, dbid
              from (
                select snap_id, dbid,
                       row_number() over (order by snap_id desc) as row_num 
                from (
                  select distinct snap_id, dbid 
                  from awr_pdb_snapshot 
                  where dbid=:v_dbid and :v_dbid != &db_dbid
                )
              ) 
              where row_num=2
            ) ssn 
            where sn.snap_id=ssn.snap_id
            and sn.dbid=ssn.dbid
            and sn.dbid=:v_dbid and :v_dbid != &db_dbid
          ) smx,
          ( 
            select sysdate max_time,
             nvl(min(end_interval_time - 1/172800), sysdate - 1/24) min_time,
                   sysdate - 5/1440 start_time
            from v$database d
            left outer join awr_pdb_snapshot h on  d.dbid=h.dbid
            where d.dbid=:v_dbid and :v_dbid=&db_dbid
          ) rmx
        ) where :pdb_type = 2
        UNION ALL
        select to_char(start_time, :date_fmt) start_time,
               to_char(max_time,:date_fmt) end_time,
               to_char(min_time, :date_fmt) a_start_time
        from (
          select case :v_dbid when &db_dbid then rmx.max_time
                              else mx.max_time 
                 end max_time, 
                 case :v_dbid when &db_dbid then rmx.min_time
                              else mx.min_time 
                 end min_time, 
                 case :v_dbid when &db_dbid then rmx.start_time
                      else greatest(nvl(smx.sec_max_time, mx.max_time - 1/24), 
                                            mx.min_time
                                   )
                 end start_time
          from (
            select max(end_interval_time + 1/172800) max_time,
                   min(end_interval_time - 1/172800) min_time
            from awr_root_snapshot    
            where dbid=:v_dbid and :v_dbid != &db_dbid
          ) mx, 
          (
            select max(end_interval_time +  1/172800) sec_max_time
            from awr_root_snapshot sn, (
              select snap_id, dbid
              from (
                select snap_id, dbid,
                       row_number() over (order by snap_id desc) as row_num 
                from (
                  select distinct snap_id, dbid 
                  from awr_root_snapshot 
                  where dbid=:v_dbid and :v_dbid != &db_dbid
                )
              ) 
              where row_num=2
            ) ssn 
            where sn.snap_id=ssn.snap_id
            and sn.dbid=ssn.dbid
            and sn.dbid=:v_dbid and :v_dbid != &db_dbid
          ) smx,
          ( 
            select sysdate max_time,
              nvl(min(end_interval_time - 1/172800), sysdate - 1/24) min_time,
                   sysdate - 5/1440 start_time
            from v$database d
            left outer join awr_root_snapshot h on  d.dbid=h.dbid
            where d.dbid=:v_dbid and :v_dbid=&db_dbid
          ) rmx
        ) where :pdb_type = 0 
       ) a ;

-- instructions for time range selection
prompt 
prompt Specify selected time range
prompt ~~~~~~~~~~~~~~~~~~~~~~~~~~~
prompt *  If the selected time range is in the past hour, report data will be 
prompt *    retrieved from V$ views.
prompt *  If the selected time range is over 1 hour ago, report data
prompt *    will be retrieved from AWR.
prompt *  If the dbid selected is not for the current database, only AWR data 
prompt *    is available.
prompt *
prompt *  Valid input formats:
prompt *      To specify absolute time:
prompt *        [mm/dd[/yyyy]] hh24:mi[:ss] 
prompt *        Examples: 02/23/14 14:30:15
prompt *                  02/23 14:30:15
prompt *                  14:30:15
prompt *                  14:30
prompt *      To specify relative time: (start with '-' sign)
prompt *        -[hh24:]mi                
prompt *        Examples: -1:15  (SYSDATE - 1 Hr 15 Mins)
prompt *                  -25    (SYSDATE - 25 Mins)
prompt
accept selected_start_time prompt "Please enter start time [&start_time]: "
prompt
accept selected_end_time prompt "Please enter end time [&end_time]: "
prompt

whenever sqlerror exit;
var v_in_starttime varchar2(19);
var v_in_endtime varchar2(19);
declare
  -- the function to get date from input
  FUNCTION get_time_from_input( btime_in IN VARCHAR2 )
    RETURN DATE
  IS
    first_char    VARCHAR2(2);
    in_str        VARCHAR2(100);

    past_hrs      NUMBER;
    past_mins     NUMBER;
    pos           NUMBER;

    num_slashes   NUMBER := 0;
    num_colons    NUMBER := 0;
    date_part     VARCHAR2(100);
    time_part     VARCHAR2(100);

    my_fmt        VARCHAR2(100) := 'MM/DD/YYYY HH24:MI:SS';
  BEGIN
    in_str := TRIM(btime_in);
    first_char := SUBSTR(in_str, 1, 1);

    /* Handle relative input format starting with a -ve sign, first */
    IF (first_char = '-') THEN
      in_str := SUBSTR(in_str, 2);
      pos := INSTR(in_str,':');
      IF (pos = 0) THEN
        past_hrs := 0;
        past_mins := TO_NUMBER(in_str);
      ELSE
        past_hrs := TO_NUMBER(SUBSTR(in_str,1,pos-1));
        past_mins := TO_NUMBER(SUBSTR(in_str,pos+1));
      END IF;
      
      IF (past_mins = 0 AND past_hrs = 0) THEN
        /* Invalid input */
        raise_application_error( -20500, 
                                 'Invalid input! Cannot recognize ' ||
                                 'input format for begin_time ' || '"' || 
                                 TRIM(btime_in) || '"' );
        RETURN NULL;
      END IF;

      RETURN (sysdate - past_hrs/24 - past_mins/1440);
    END IF;

    /* Handle absolute input format now.
       Fill out all the missing optional parts of the input string
       to make it look like 'my_fmt' first. Then just do "return to_date()".
     */
    FOR pos in 1..LENGTH(in_str) LOOP
      IF (SUBSTR(in_str,pos,1) = '/') THEN
        num_slashes := num_slashes + 1;
      END IF;
      IF (SUBSTR(in_str,pos,1) = ':') THEN
        num_colons := num_colons + 1;
      END IF;
    END LOOP;

    IF (num_slashes > 0) THEN
      pos := INSTR(in_str,' ');
      date_part := TRIM(SUBSTR(in_str,1,pos-1));
      time_part := TRIM(SUBSTR(in_str,pos+1));

      IF (num_slashes = 1) THEN
        date_part := date_part || '/' || TO_CHAR(sysdate,'YYYY');
      END IF;
    ELSE
      date_part := TO_CHAR(sysdate,'MM/DD/YYYY');
      time_part := in_str;
    END IF;

    IF (num_colons > 0) THEN
      IF (num_colons = 1) THEN
        time_part := time_part || ':00';
      END IF;
      in_str := date_part || ' ' || time_part;
      begin
        RETURN TO_DATE(in_str, my_fmt);
      exception
        when others then
        /* Invalid input */
        raise_application_error( -20500, 
                                 'Invalid input! Cannot recognize ' ||
                                 'input format for time ' || '"' || 
                                 TRIM(btime_in) || '"' );
      end;
    END IF;

    /* Invalid input */
    raise_application_error( -20500, 
                             'Invalid input! Cannot recognize ' ||
                             'input format for time ' || '"' || 
                             TRIM(btime_in) || '"' );
    RETURN NULL;

  END get_time_from_input;

begin
  :v_in_endtime := to_char(
                     get_time_from_input(
                       nvl('&&selected_end_time' , '&end_time')
                     ),
                     :date_fmt
                   );
  :v_in_starttime := to_char(
                     get_time_from_input(
                        nvl('&&selected_start_time' , '&start_time')
                     ),
                     :date_fmt
                   );
end;
/
whenever sqlerror continue;

-- determine time range selection
set heading off;
var v_selected_start_time varchar2(19);
var v_selected_end_time varchar2(19);
var v_outer_start_time varchar2(19);
var v_outer_end_time varchar2(19);
var v_is_realtime number;
var v_selected_interval number;
var v_outer_interval number;
begin
    -- determine whether realtime or not
    -- determine selected end time - earliest between user input
    -- and available end time
    select to_char(selected_end_time,:date_fmt),
           to_char(selected_end_time, :date_fmt), 
           case 
             when selected_end_time < sysdate - 1/24
               then 0
             else 1 
           end is_realtime
      into :msg, :v_selected_end_time, :v_is_realtime
    from (
      select case when selected_end_time < a_start_time 
                       or selected_end_time > end_time
                    then end_time
                  else selected_end_time
             end selected_end_time,
             end_time,
             start_time
      from (
      -- convert string to date
        select to_date(:v_in_endtime, :date_fmt) selected_end_time,
               to_date('&end_time', :date_fmt) end_time,
               to_date('&start_time', :date_fmt) start_time,
               to_date('&a_start_time', :date_fmt) a_start_time
        from sys.dual
      )
    );

   -- override: for imported data, we always generate historical report
    if (sys.dbms_sqltune_util2.resolve_database_type(:v_dbid)  
         = sys.dbms_sqltune_util2.DB_TYPE_IMP) 
    then
       :v_is_realtime := 0;
    end if;

    -- determine default intervals
    select case :v_is_realtime when 1 then 5/1440 else 1/24 end,
           case :v_is_realtime when 1 then 1/24 else 1 end
    into :v_selected_interval, :v_outer_interval
    from sys.dual;
end;
/

set heading on;
set termout off;
-- adjust a_start_time for realtime
select case :v_is_realtime 
         when 1 then to_char(
                       to_date('&end_time', :date_fmt) - 1/24, 
                       :date_fmt)
         else '&a_start_time'
       end a_start_time
from sys.dual;

set termout on;
set heading off;

begin

  -- validate start time
  -- if it is earlier than selected end time, set it to 
  -- end time - default interval; if it is earlier than 
  -- available start time, set it to available start time
  select to_char(
             greatest(selected_start_time, a_start_time),
           :date_fmt)
  into :v_selected_start_time
  from (             
    select selected_end_time,
           case when selected_start_time > selected_end_time
                  then selected_end_time - :v_selected_interval
                when selected_start_time < a_start_time
                  then a_start_time
                else selected_start_time
           end selected_start_time,
           end_time,
           start_time,
           a_start_time
    from (
      select to_date(:v_selected_end_time, 
                     :date_fmt) selected_end_time,
             to_date(:v_in_starttime, :date_fmt) selected_start_time,
             to_date('&end_time', :date_fmt) end_time,
             to_date('&start_time', :date_fmt) start_time,
             to_date('&a_start_time', :date_fmt) a_start_time
        from sys.dual
    )
  );
  -- outer end time is default end time in realtime or
  -- selected end time in historical mode
  -- outer start time is default start time in realtime or
  --   or selected start time in historical mode
  select to_char(
           case :v_is_realtime when 1
             then end_time
             else selected_end_time
           end, 
           :date_fmt
         ) outer_end_time,
         to_char(
           case :v_is_realtime when 1
             then a_start_time
             else greatest(
                    a_start_time, 
                    least(
                      selected_start_time, 
                      selected_end_time-:v_outer_interval
                    )
                  )
           end,
           :date_fmt
         ) outer_start_time
  into :v_outer_end_time,
       :v_outer_start_time
  from (    
    select to_date(:v_selected_end_time, :date_fmt) selected_end_time,
           to_date(
             :v_selected_start_time, 
             :date_fmt) selected_start_time,
           to_date('&end_time', :date_fmt) end_time,
           to_date('&start_time', :date_fmt) start_time,
           to_date('&a_start_time', :date_fmt) a_start_time
      from sys.dual
  );

  -- construct message
  select 'Generating report for ' || :v_selected_start_time  
           || ' - ' || :msg
  into :msg
  from sys.dual;
end;
/
print :msg;

-- default report name
column rpt_name new_value rpt_name format a100;

set termout off;
select 'perfhub_'
         || case :v_is_realtime 
              when 1 then 'rt_' 
              else 'ht_' 
            end
         || case when :v_inst_id is null then ''
                 else :v_inst_id || '_'
            end
         || to_char(to_date(:v_selected_end_time, :date_fmt), 'mmddhh24mi')
         || '.html' rpt_name
from sys.dual;
set termout on;
set heading on;

-- prmpt for report name
prompt 
prompt Specify the Report Name
prompt ~~~~~~~~~~~~~~~~~~~~~~~
accept report_name prompt "Please enter report name [&rpt_name]: "
prompt

set heading off;
column report_name new_value report_name noprint
select 'Generating report ' || nvl('&&report_name', '&rpt_name') 
         || ' ...',
       nvl('&&report_name', '&rpt_name') report_name
from sys.dual;
set heading on;

-- turn off compression
-- alter session set events 'emx_control compress_xml=none';

set termout off;
SET TRIMSPOOL ON
SET TRIM ON
SET PAGESIZE 0 LINESIZE 32767
set long 10000000 longchunksize 10000000
SET VERIFY OFF
set heading off;
set underline off;

-- generate the report
spool &report_name create;

select dbms_perf.report_perfhub(is_realtime=>:v_is_realtime,
                         outer_start_time=>
                           to_date(:v_outer_start_time, :date_fmt),
                         outer_end_time=>
                           to_date(:v_outer_end_time, :date_fmt),
                         selected_start_time=>
                           to_date(:v_selected_start_time, :date_fmt),
                         selected_end_time=>
                           to_date(:v_selected_end_time, :date_fmt),
                         inst_id=>:v_inst_id,
                         dbid=>:v_dbid,
                         report_level=>:v_rpt_level,
                         con_name => :v_con_name)
from sys.dual;

spool off;

set termout on;
prompt
prompt Report written to &report_name.
prompt

undefine report_level;
undefine dbid;
undefine inst_id;
undefine inst_prompt;
undefine selected_end_time;
undefine selected_start_time;
undefine report_name;

set underline on
set verify on

set long 80 longchunksize 80
set pagesize 60;
set linesize 78 termout on feedback 6 heading on;

OHA YOOOO