----------------------------------------------------------------------------------------
--
-- File name:   cs_dg_protection_mode_switches.sql
--
-- Purpose:     Data Guard Protection Mode Switches as per Log Archive Dest
--
-- Author:      Carlos Sierra
--
-- Version:     2021/10/18
--
-- Usage:       Execute connected to CDB or PDB
--
-- Example:     $ sqlplus / as sysdba
--              SQL> @cs_dg_protection_mode_switches.sql
--
-- Notes:       Developed and tested on 12.1.0.2.
--
---------------------------------------------------------------------------------------
--
@@cs_internal/cs_primary.sql
@@cs_internal/cs_set.sql
@@cs_internal/cs_def.sql
@@cs_internal/cs_file_prefix.sql
--
DEF cs_script_name = 'cs_dg_protection_mode_switches';
--
SELECT '&&cs_file_prefix._&&cs_script_name.' cs_file_name FROM DUAL;
--
@@cs_internal/cs_spool_head.sql
PRO SQL> @&&cs_script_name..sql 
@@cs_internal/cs_spool_id.sql
--
@@cs_internal/&&cs_set_container_to_cdb_root.
--
COL begin_time FOR A19 HEA 'AWR SNAP|BEGIN TIME';
COL end_time FOR A19 HEA 'AWR SNAP|END TIME';
COL begin_host FOR A64 HEA 'AWR SNAP|BEGIN STANDBY HOST';
COL end_host FOR A64 HEA 'AWR SNAP|END STANDBY HOST';
COL min_date_time FOR A19 HEA 'LOGON STORM|BEGIN TIME';
COL max_date_time FOR A19 HEA 'LOGON STORM|END TIME';
COL max_aas FOR 99,999 HEA 'LOGON STORM|MAX AAS';
COL max_machines FOR 999,990 HEA 'LOGON STORM|MAX AAS';
COL seconds FOR 999,990 HEA 'LOGON STORM|SECONDS';
COL max_pdbs FOR 999,990 HEA 'LOGON STORM|MAX PDBS';
COL begin_mode FOR A15 HEA 'AWR SNAP|BEGIN MODE';
COL end_mode FOR A15 HEA 'AWR SNAP|END MODE';
COL mode_switch FOR A7 HEA 'MODE|SWITCH';
COL switch_over FOR A7 HEA 'SWITCH|OVER';
--
BREAK ON mode_switch SKIP 1 DUPL;
--
PRO
PRO DG PROTECTION MODE SWITCHES
PRO ~~~~~~~~~~~~~~~~~~~~~~~~~~~
WITH
parameter_hist AS (
SELECT /*+ MATERIALIZE NO_MERGE */
       h.snap_id,
       h.dbid,
       h.instance_number,
       h.parameter_name,
       LAG(h.value) OVER (PARTITION BY h.dbid, h.instance_number, h.parameter_name, h.con_id ORDER BY h.snap_id) AS prior_value,
       h.value,
       h.con_id
  FROM dba_hist_parameter h
 WHERE parameter_name LIKE 'log_archive_dest%'
   AND parameter_name NOT LIKE 'log_archive_dest_state%'
),
parameter_changes AS (
SELECT /*+ MATERIALIZE NO_MERGE */
       h.snap_id,
       h.dbid,
       h.instance_number,
       h.parameter_name,
       h.prior_value,
       h.value,
       REPLACE(REPLACE(REGEXP_SUBSTR(h.prior_value, '\(HOST=([[:alnum:]]|\.|-)+\)'), '(HOST='), ')') AS begin_host,
       REPLACE(REPLACE(REGEXP_SUBSTR(h.value, '\(HOST=([[:alnum:]]|\.|-)+\)'), '(HOST='), ')') AS end_host,
       CASE 
         WHEN h.prior_value LIKE '% SYNC AFFIRM %' THEN 'SYNC AFFIRM' 
         WHEN h.prior_value LIKE '% ASYNC AFFIRM %' THEN 'ASYNC AFFIRM' -- not expected
         WHEN h.prior_value LIKE '% SYNC NOAFFIRM %' THEN 'SYNC NOAFFIRM'  -- not expected
         WHEN h.prior_value LIKE '% ASYNC NOAFFIRM %' THEN 'ASYNC NOAFFIRM'
       END AS begin_mode, 
       CASE 
         WHEN h.value LIKE '% SYNC AFFIRM %' THEN 'SYNC AFFIRM' 
         WHEN h.value LIKE '% ASYNC AFFIRM %' THEN 'ASYNC AFFIRM' -- not expected
         WHEN h.value LIKE '% SYNC NOAFFIRM %' THEN 'SYNC NOAFFIRM'  -- not expected
         WHEN h.value LIKE '% ASYNC NOAFFIRM %' THEN 'ASYNC NOAFFIRM'
       END AS end_mode,
       h.con_id,
       s.begin_interval_time,
       s.end_interval_time
  FROM parameter_hist h,
       dba_hist_snapshot s
 WHERE NVL(h.value, '-666') <> NVL(h.prior_value, '-666')
   AND h.prior_value LIKE '%(HOST=%'
   AND h.value LIKE '%(HOST=%'
   AND s.snap_id = h.snap_id
   AND s.dbid = h.dbid
   AND s.instance_number = h.instance_number
),
dg_mode_switches AS (
SELECT CAST(p.begin_interval_time AS DATE) AS begin_time,
       CAST(p.end_interval_time AS DATE) AS end_time,
       p.begin_mode,
       p.end_mode,
       p.begin_host,
       p.end_host
  FROM parameter_changes p
),
over_height AS (
SELECT /*+ MATERIALIZE NO_MERGE */
       h.sample_time,
       COUNT(*) AS aas,
       COUNT(DISTINCT machine) AS machines, 
       COUNT(DISTINCT con_id) AS pdbs,
       (CAST(h.sample_time AS DATE) - LAG(CAST(h.sample_time AS DATE)) OVER (ORDER BY h.sample_time)) * 24 * 3600 AS secs_from_prior
  FROM dba_hist_active_sess_history h
 GROUP BY
       h.sample_time
HAVING COUNT(*) > 1000 -- active sessions!
),
over_time AS (
SELECT CAST(h.sample_time AS DATE) AS sample_time,
       h.aas,
       h.machines,
       h.pdbs
  FROM over_height h
 WHERE secs_from_prior < 20 -- contiguous
),
logon_storms AS (
SELECT TRUNC(sample_time) AS date_time,
       MIN(sample_time - (20/24/3600)) AS min_date_time,
       MAX(sample_time) AS max_date_time,
       ((MAX(sample_time) - MIN(sample_time)) * 24 * 3600) + 20 AS seconds,
       MAX(aas) AS max_aas,
       MAX(machines) AS max_machines,
       MAX(pdbs) AS max_pdbs
  FROM over_time
 GROUP BY
       TRUNC(sample_time)
)
SELECT dg.begin_time,
       dg.end_time,
       dg.begin_mode,
       dg.end_mode,
       CASE dg.begin_mode WHEN 'ASYNC NOAFFIRM' THEN 'HP' WHEN 'SYNC AFFIRM' THEN 'HA' END||'->'||
       CASE dg.end_mode WHEN 'ASYNC NOAFFIRM' THEN 'HP' WHEN 'SYNC AFFIRM' THEN 'HA' END AS mode_switch,
       ls.min_date_time,
       ls.max_date_time,
       ls.seconds,
       ls.max_aas,
       ls.max_pdbs,
       dg.begin_host,
       dg.end_host,
       CASE WHEN dg.begin_host <> dg.end_host THEN 'YES' ELSE 'NO' END AS switch_over
  FROM dg_mode_switches dg
       OUTER APPLY (
         SELECT s.min_date_time,
                s.max_date_time,
                s.seconds,
                s.max_aas,
                s.max_pdbs
           FROM logon_storms s
          WHERE (s.min_date_time BETWEEN dg.begin_time AND dg.end_time OR s.max_date_time BETWEEN dg.begin_time AND dg.end_time)
            AND ROWNUM >= 1 /* MATERIALIZE NO_MERGE */
          ORDER BY
                s.min_date_time ASC
          FETCH FIRST 1 ROW ONLY
       ) ls
 ORDER BY
       dg.begin_time
/
--
PRO
PRO SQL> @&&cs_script_name..sql 
--
@@cs_internal/cs_spool_tail.sql
--
@@cs_internal/&&cs_set_container_to_curr_pdb.
--
@@cs_internal/cs_undef.sql
@@cs_internal/cs_reset.sql
--