Rem $Header: rdbms/admin/preupgrade_package.sql /st_rdbms_12.2.0.1.0dbbp/2 2017/06/15 12:07:39 sschodav Exp $
Rem
Rem preupgrade_package.sql
Rem
Rem Copyright (c) 2015, 2017, Oracle and/or its affiliates. 
Rem All rights reserved.
Rem
Rem    NAME
Rem      preupgrade_package.sql - Pre Upgrade Utility Package
Rem
Rem    DESCRIPTION
Rem      Procedures and functions used to perform checks on a database which
Rem      is getting ready to be upgraded.
Rem
Rem    NOTES
Rem      This file contains both the package body and defintion.
Rem
Rem
Rem    MODIFIED   (MM/DD/YY)
Rem    apfwkr      05/23/17 - Backport raeburns_bug-25044977 from main
Rem    apfwkr      04/06/17 - Backport bymotta_bug-24923215 from main
Rem    frealvar    11/09/16 - Backport frealvar_bug-25038937 from main
Rem    cmlim       11/06/16 - Backport cmlim_bug-24696626 from
Rem                           st_rdbms_12.2.0.1.0
Rem    frealvar    11/03/16 - Backport frealvar_lrg-19787764 from main
Rem    amunnoli    10/18/16 - Backport amunnoli_bug-24741114 from main
Rem    frealvar    10/18/16 - Backport frealvar_bug-24695433 from
Rem                           st_rdbms_12.2.0.1.0
Rem    frealvar    10/16/16 - bug 24835864 backport of RTI 19787195 fix query that
Rem                           feeds all_parameters 
Rem    hvieyra     10/14/16 - Backport hvieyra_bug-20950535 from main
Rem    frealvar    09/25/16 - Bug 24695433 temp tablespace without temp file
Rem    cmlim       08/18/16 - bug 24448551: for now, do not recommend
Rem                           pga_aggregate_limit if value was default
Rem    bymotta     12/02/16 - Bug 24923215: Set statistics concurrent to off
Rem                           when Concurrent is enabled but no Resource
Rem                           Manager configuration is enabled
Rem    raeburns    11/26/16 - Bug 25044977: add post-upgrade check for
Rem                           dependent tables
Rem                           Bug 25262869: add NOCYCLE to dependency$ query
Rem    frealvar    11/11/16 - Bug 25038937 fix missed tempfile issue in query
Rem    frealvar    10/27/16 - LRG 19787764 increased max line length in xml
Rem    amunnoli    10/02/16 - Bug 24741114: do not error out for aud$unified
Rem                           table partitions
Rem    hvieyra     09/07/16 - Bug 20950535. Check if JAVAVM mitigation
Rem                           patch is installed in the database.
Rem    hvieyra     08/12/16 - Fix for bug 23573843. Manage obsolete/deprecated 
Rem                           parameters that were defaulted at database startup
Rem                           but got set to spfile via alter system.
Rem    frealvar    08/10/16 - Bug 24400584 update obsolete/deprecated parameters
Rem    arvijaya    08/03/16 - Bug 24398111:exclude_seed_cdb_view obso.lete 12201
Rem    arvijaya    08/03/16 - Bug 24398111:exclude_seed_cdb_view obsolete 12201
Rem    ewittenb    08/01/16 - XbranchMerge ewittenb_postup from main
Rem    bymotta     07/27/16 - Bug 24012143: Postupgrade_fixups.sql some checks
Rem                           are not working properly. Adding automatic statistics run
Rem                           in the postfixup script, also if those statistics have been run
Rem                           posftfixup will not report it again.
Rem    ewittenb    07/13/16 - bug 24340891 and 23641965 dbms_preup and preupgrade_dir must
Rem                           be present
Rem    cmlim       06/23/16 - bug 23224075: update system/sysaux sizes; update
Rem                           archive + flashback log xml info and minimum sizes
Rem    ewittenb    06/22/16 - make run_fixup_and_report() package visible.
Rem    cmlim       06/16/16 - bug 23596360: pdbs_para cannot be 0 
Rem    bymotta     06/13/16 - Bug: 23573843 Adding Obsolete parameters
Rem    amunnoli    06/07/16 - Bug 23539027: Fix wallet query to work in 11.2
Rem    amunnoli    05/31/16 - Bug 23221566: check audit tables in encrypted ts
Rem    bymotta     05/20/16 - Bug 23278082: Add null management on a query that
Rem                           as of 12.2 will not return any value
Rem    cmlim       05/11/16 - bug 23185159: convert archive/fra info to checks
Rem    frealvar    05/10/16 - correction for fixed_objects_check
Rem    bymotta     05/10/16 - Wrong query on files_backup_mode_check fucntion
Rem    ewittenb    05/04/16 - bug 23216475
Rem    ewittenb    04/21/16 - Bug 23000563 - generation of
Rem                           preupgrade_fixups.sql and postupgrade_fixups.sql
Rem    kaizhuan    04/19/16 - lrg 19415919: check PA views existence before
Rem                           querying the views.
Rem    frealvar    04/10/16 - Bug 20669175 check for any pending dst session
Rem                           before upgrade
Rem    ewittenb    04/11/16 - Add APEX_PATCH check and tweak other surrounding
Rem                           APEX issues.
Rem    frealvar    04/10/16 - Bug 23064794 deprecated/obsoleted parameters
Rem    frealvar    04/10/16 - Bug 20984980 databases edition into the log
Rem    cmlim       04/09/16 - bug 22128117: memory sizing for upgrade to 12.2
Rem    frealvar    03/25/16 - Bug 22695570 change check for postupgrade_fixups
Rem    kaizhuan    03/23/16 - Bug 22862142: add check for Privilege Analysis
Rem    pknaggs     03/09/16 - Bug #20847187: Exclusive Mode checks for 12.2
Rem    amunnoli    03/09/16 - Bug 22899818: Check for oracle maintained bit
Rem    yanchuan    03/06/16 - Bug 20505982: remove warning message
Rem                           about disable Database Vault
Rem    hvieyra     03/02/16 - Fix for bug 22708956- Add check to detect
Rem                           datamining data in customer tablespace
Rem    tojhuan     03/02/16 - 22744959: make xdb_resource_type_check compatible
Rem                           with databases not having XDB installed
Rem    raeburns    02/29/16 - Bug 22820096: revert ALTER TYPE to default
Rem                           CASCADE
Rem    frealvar    02/15/16 - Bug 22360200  ora-06502: buffer too small
Rem    ewittenb    02/11/16 - add run_fixup_and_report() for backward
Rem                           compatibility
Rem    raeburns    02/03/16 - Bug 22322252: Add pre-upgrade check for USER
Rem                           tables dependent on Oracle-Maintained types
Rem    ewittenb    01/29/16 - use INTEGER instead of NUMBER to retain large
Rem                           scale > 32 bits and without fractions
Rem    bymotta     01/19/16 - Bug 22471732, Fix for upgrade.xml file
Rem                           truncation.
Rem    welin       01/28/15 - fix bad /main/35 with main/37
Rem    schakkap    12/23/15 - #(22454765) add check for dbms_stats method_opt
Rem                           preference
Rem    sramakri    12/15/15 - bug-22166873: check for mv refresh
Rem    welin       12/14/15 - Bug 21531270: Gather dictionary stats post upgrade
Rem    frealvar    12/10/15 - 22220833 fix call to DBMS_PREUP.PURGE_RECYCLEBIN_FIXUP
Rem                           and removed nested queries in init_resources
Rem    ewittenb    12/10/15 - exclude OFFLINE NORMAL files from
Rem                           files_need_recovery_check
Rem    rpang       12/02/15 - Bug 22292132: network_acl_priv_check return value
Rem    bymotta     11/25/15 - Bug 22125093: UPGRADE:SOME PDBS PREUPGRADE LOG
Rem                           ARE MISSING, adding messages to explain why the
Rem                           logs were not created, mostly because the DB/PDB
Rem                           was not opened.
Rem    ssonawan    11/25/15 - 21289647: REMOTE_LOGIN_PASSWORDFILE check
Rem    frealvar    11/10/15 - 22174779: changed logic used in store_removed_param
Rem                           and added utl_file_dir to the deprecated param list
Rem    rpang       10/23/15 - Bug 22061588: 12.1 network ACL migration check
Rem    frealvar    10/22/15 - frealvar_read_only_db_state: moved functions from
Rem                           preupgrade_package to dbms_registry_extended,
Rem                           linesize modified, added improvements into procedure
Rem                           store_comp and removed function is_db_readonly
Rem    frealvar    10/28/15 - 21849635: change the placeholder format used
Rem    tojhuan     10/12/15 - 21795185: if XDB.XDB$RESOURCE_T has incorrect-
Rem                           ordered attributes CheckedOutByID/BaseVersion,
Rem                           check whether we can fix it during upgrade
Rem    ewittenb    10/07/15 - fix wrong version numbers in
Rem                           oracle_reserved_users
Rem    frealvar    10/01/15 - removed references to registry$sys_inv_objs from
Rem                           invalid_objects_exist check
Rem    ewittenb    09/30/15 - fix archivelogs text output
Rem    bymotta     09/28/15 - Bug 21902277: Some auto-fixup actions are not
Rem                           working properly, this transaction makes sure all
Rem                           auto-fixups will work as expected.
Rem    ewittenb    09/28/15 - make minor tweaks as part of message enhancement
Rem    frealvar    08/25/15 - bug 21646111 check for trigger owner with no 
Rem                           administer database trigger privilege
Rem                           if the compatible value was not explicitly set
Rem    frealvar    08/24/15 - bug 21529376 added two new checks which verify
Rem                           parameters pga_aggregate_target and pga_aggregate_limit
Rem    bymotta     09/23/15 - Bug 21843339 - fix to avoid fetch when awr
Rem                           contans more than one dbid
Rem    ewittenb    09/03/15 - Modify to fix output text for rollback segments
Rem                           port fixes for bugs 21388784, 21688231 from
Rem                           from utluppkg.sql.
Rem    bymotta     09/01/15 - Adding functionality to preupgrade package
Rem    skayoor     08/28/15 - Bug 21388784: Mark O7_DICTIONARY_ACCESSIBILITY as
Rem                           deprecated
Rem    svaziran    08/25/15 - bug 21548817: check for application_trace_viewer
Rem    risgupta    08/25/15 - Lrg 18421763: Check whether OLS is installed in
Rem                           OLS version preupgrade check
Rem    amunnoli    08/24/15 - Bug 21688231: Update UNIAUD_TAB tag correctly
Rem    risgupta    07/31/15 - Bug 21178327: Add check whether OLS
Rem                           version is same as CATPROC version
Rem    frealvar    07/02/15 - bug 13022498 A new check which advise the user
Rem                           if the compatible value was not explicitly set
Rem    frealvar    06/04/15 - bug 20795508 Problem with minimum size for the
Rem                           temporary tablespace in the preupgrade.log
Rem    frealvar    05/25/15 - bug 21102514 invalid default temp tablespaces
Rem    namoham     05/12/15 - Bug 16570807: Include a filter to check default
Rem                           DV role conflicts
Rem    hvieyra     05/06/15 - Bug fix for 19581925 UNDO TS recommendation
Rem    rpang       04/27/15 - Bug 20723336: overlapping network ACLs check
Rem    welin       04/20/15 - lrg 15956167: Changing the preupgrade tool 
Rem                           to set Compatibility value to 11.2
Rem    bnnguyen    04/11/15 - bug 20860190: Rename 'EXADIRECT' to 'DBSFWUSER'
Rem    jorgrive    03/24/15 - add GGSYS and GGSYS_ROLE checks
Rem    hvieyra     03/20/15 - Fix Bug 20107503 - Precising CATNOAMD.SQL WARNING
Rem                           MESSAGE
Rem    welin       03/09/15 - Bug 20591183, JOB_QUEUE_PROCESS should be >0
Rem    hvieyra     02/10/15 - Bug fix for 18500508 Use 8 digits DB version
Rem    cmlim       01/25/15 - bug 19367547 - include pdb files in the output
Rem                           summary; change pdb file name format; support
Rem                           xml pdb files so dbua can run preupgrd.sql in
Rem                           parallel; drop text dir objs 
Rem    hvieyra     01/07/15 - Bug fix for 18961009 remove APEX/DV old version
Rem                           code
Rem    hvieyra     12/19/14 - Bug Fix 19873610 Non-Default Tablespace
Rem                           validation
Rem    jerrede     12/10/14 - Fix Bug 19499984 for vrecover_file within a CDB
Rem    hvieyra     12/04/14 - Bug Fix for 8889083 Database archiving display
Rem    jerrede     11/05/14 - Add more clarity to the compatibility check
Rem    bnnguyen    10/29/14 - bug 19697038: add check for EXADIRECT USER/ROLE
Rem    jorgrive    10/20/14 - Desupport Advanced Replication
Rem    cmlim       10/19/14 - lrg 13418229: latest time zone file version is 23
Rem    cmlim       10/06/14 - bug 19646646: update time zone MOS note from
Rem                           977512.1 to 1509653.1
Rem    jlingow     09/11/14 - proj-58146 add check for existing 
Rem                           remote_scheduler_agent
Rem    spapadom    08/18/14 - Added checks for SYS$UMF and SYSUMF_ROLE. 
Rem    cmlim       08/14/14 - bug 19195895: make sure inserts/updates are not
Rem                           done if db is read only
Rem    ewittenb    08/05/14 - Update for 12.2 support by removing support for
Rem                           direct upgrades from 11.2.0.2
Rem    ewittenb    07/30/15 - bring forward changes to utluppkg.sql - changes listed above
Rem    yanlili     06/23/15 - check xs_connect role for RAS
Rem    ewittenb    04/04/15 - initial port from utluppkg.sql
Rem

CREATE OR REPLACE PACKAGE dbms_preup AS

    c_build                  CONSTANT NUMBER := 005;    -- the unique build# of this package.

    --
    --    PACKAGE Constants
    --
    debug BOOLEAN := FALSE; 
    debug_archive_fra BOOLEAN := FALSE;  -- debug for archiving/fra checks
    pDBGSizeResources BOOLEAN := FALSE;

    --
    --    The result of every CHECK must be c_success or c_failure.
    --    CHECK failure severities and other attributes of
    --    a check can then be looked up on the check_record_t
    --    of the failing CHECK.
    --
    c_success    CONSTANT NUMBER := 1;
    c_failure    CONSTANT NUMBER := 2;

    --
    --    Each CHECK has one SEVERITY associated with it.
    --    That severity is only meaningful when
    --    the result of the CHECK is c_failure.
    --    NOTE: Changes to these constants or the addition
    --    of new ones should be met with a reset of
    --    check_level_strings defined further below.
    --
    c_check_level_success    CONSTANT NUMBER := 1; 
    c_check_level_warning    CONSTANT NUMBER := 2;
    c_check_level_info       CONSTANT NUMBER := 3;
    c_check_level_error      CONSTANT NUMBER := 4;
    c_check_level_recommend  CONSTANT NUMBER := 5;

    c_param_type_number      CONSTANT NUMBER := 3;
    c_param_type_number_alt  CONSTANT NUMBER := 6;
    c_param_type_string      CONSTANT NUMBER := 2;
    c_param_type_version     CONSTANT NUMBER := -1;
    c_param_type_other       CONSTANT NUMBER := 0;
   
     
    C_FIXUP_SCRIPT_NAME_PRE_BASE    CONSTANT VARCHAR2(30) := 'preupgrade_fixups'; 
    C_FIXUP_SCRIPT_NAME_PRE VARCHAR2(256);

    C_FIXUP_SCRIPT_NAME_POST_BASE   CONSTANT VARCHAR2(30) := 'postupgrade_fixups'; 
    C_FIXUP_SCRIPT_NAME_POST VARCHAR2(256);

    --
    -- surrounds the substitution number, i.e. {1}, {2}, etc.
    -- inside a check message.
    --
    C_SUBSTITUTION_DELIMITER_OPEN  CONSTANT CHAR(1) := '{';
    C_SUBSTITUTION_DELIMITER_CLOSE CONSTANT CHAR(1) := '}';

    --
    -- indexes (by pool names) into mem_parameters table for the given pools
    --
    cs_idx CONSTANT V$PARAMETER.NAME%TYPE := 'db_cache_size';
    jv_idx CONSTANT V$PARAMETER.NAME%TYPE := 'java_pool_size';
    sp_idx CONSTANT V$PARAMETER.NAME%TYPE := 'shared_pool_size';
    lp_idx CONSTANT V$PARAMETER.NAME%TYPE := 'large_pool_size';
    sr_idx CONSTANT V$PARAMETER.NAME%TYPE := 'streams_pool_size';
    pt_idx CONSTANT V$PARAMETER.NAME%TYPE := 'pga_aggregate_target';
    st_idx CONSTANT V$PARAMETER.NAME%TYPE := 'sga_target';
    mt_idx CONSTANT V$PARAMETER.NAME%TYPE := 'memory_target';

    -- minimum flashback log size (in Kbytes) generated per pdb
    C_MIN_FLASHBACK_KB_PER_PDB   CONSTANT NUMBER := 333 * 1024;

    --
    --    PACKAGE Exceptions
    --
    e_noColumnFound EXCEPTION;
    PRAGMA exception_init(           e_noColumnFound,          -904);

    nameAlreadyExists EXCEPTION;
    PRAGMA exception_init(           nameAlreadyExists,        -955);

    e_userCancel EXCEPTION;
    PRAGMA exception_init(           e_userCancel,            -1013);

    e_noParamFound EXCEPTION;
    PRAGMA exception_init(           e_noParamFound,          -2003);

    e_noOraConnect1 EXCEPTION;
    PRAGMA exception_init(           e_noOraConnect1,         -3113);

    e_noOraConnect2 EXCEPTION;
    PRAGMA exception_init(           e_noOraConnect2,         -3114);

    e_undefinedFunction EXCEPTION;
    PRAGMA exception_init(           e_undefinedFunction,     -6550);

    invalidFileOperation EXCEPTION;
    PRAGMA exception_init(           invalidFileOperation,   -29283);

    invalidFileRename EXCEPTION;
    PRAGMA exception_init(           invalidFileRename,      -29292);

    classInUse EXCEPTION;
    PRAGMA exception_init(           classInUse,             -29553);

    stringNotSimpleSQLName EXCEPTION;
    PRAGMA exception_init(           stringNotSimpleSQLName, -44003);

    --
    --    PACKAGE TYPEs
    --

    TYPE string_array_t IS TABLE OF VARCHAR2(4000);
    TYPE string_array_collection_t IS TABLE OF VARCHAR2(4000) INDEX BY BINARY_INTEGER;
    TYPE detail_t IS RECORD (
        detail       VARCHAR2(4000),
        detail_type  VARCHAR2(30)
    );

    TYPE number_array_t IS TABLE OF NUMBER;

    TYPE messagevalue_t is RECORD (
        position NUMBER,
        value VARCHAR2(4000)
    );

    TYPE messagevalues_t IS TABLE OF messagevalue_t INDEX BY BINARY_INTEGER;
    TYPE message_t is RECORD (
        -- msg_text      VARCHAR2(4000),    -- aka the RULE
        -- cause         VARCHAR2(4000),    -- aka the BROKEN_RULE
        -- action        VARCHAR2(4000),
        -- detail        detail_t
        id            VARCHAR2(4000),
        messagevalues messagevalues_t
    );

    TYPE fixup_t IS RECORD (
        fixup_type VARCHAR2(30),
        fixAtStage VARCHAR2(30)
    );

    TYPE component_t IS RECORD (
      cid            VARCHAR2(30), -- component id
      cname          VARCHAR2(45), -- component name
      script         VARCHAR2(128), -- upgrade script name
      version        VARCHAR2(30), -- version
      status         VARCHAR2(15),  -- component status
      install        BOOLEAN
    );

    TYPE components_t IS TABLE OF component_t INDEX BY BINARY_INTEGER;

    TYPE tablespace_t IS RECORD (
        name         VARCHAR2(128),
        additional_size INTEGER,
        min             INTEGER,
        alloc           INTEGER,
        inc_by          INTEGER,
        fauto           BOOLEAN,
        contents        SYS.dba_tablespaces.contents%type
    );

    TYPE tablespaces_t IS TABLE OF tablespace_t INDEX BY BINARY_INTEGER;

    TYPE archivelogs_t IS RECORD (
        name         VARCHAR2(128),
        additional_size INTEGER
    );

    TYPE flashbacklogs_t IS RECORD (
        name         VARCHAR2(128),
        additional_size INTEGER
    );

    TYPE rollback_segment_t IS RECORD (
        name         VARCHAR2(128),
        tablespc     VARCHAR2(128),
        status       VARCHAR2(31),
        auto         INTEGER,
        inuse        INTEGER,
        next         INTEGER,
        max_ext      INTEGER
    );

    TYPE rollback_segments_t IS TABLE OF rollback_segment_t INDEX BY BINARY_INTEGER;

    TYPE flashback_info_t IS RECORD (
        name           V$RECOVERY_FILE_DEST.NAME%TYPE, -- name
        limit          INTEGER,       -- space limit
        used           INTEGER,       -- Used
        dsize          INTEGER,       -- db_recovery_file_dest_size
        reclaimable    INTEGER,
        files          INTEGER,       -- number of files
        min_fra_size   INTEGER        -- min db_recovery_file_dest_size to set
    );

    TYPE fra_info_t IS RECORD (
        name                V$RECOVERY_FILE_DEST.NAME%TYPE, -- name/path
        limit               INTEGER,  -- db_recovery_file_dest_size (bytes)
        used                INTEGER,  -- Used (bytes)
        dsize               INTEGER,  -- destination size
        reclaimable         INTEGER,  -- bytes reclaimable
        files               INTEGER,  -- number of files
        avail               INTEGER,  -- bytes available in FRA
        min_archive_gen     INTEGER,  -- minimum archive logs (bytes) estimated
                                      --   to be generate during upgrade
        min_flashback_gen   INTEGER,  -- rough minimum flashback logs (bytes)
                                      --   to be generated during upgrade
        min_fra_size        INTEGER,  -- new db_recovery_file_dest_size to set
        min_freespace_reqd  INTEGER,  -- min free space needed for logs
                                      -- to be generated during upgrade
        additional_size     INTEGER   -- additional size + limit = min_fra_size
    );

    -- TYPE ARCHive DESTination RECORD Type
    -- stores info from v$archive_dest if there's at least 1 non-fra destination
    TYPE archiveDest_info_t IS RECORD (
      dest_name          V$ARCHIVE_DEST.DEST_NAME%TYPE, -- log_archive_dest_<N>
      destination        V$ARCHIVE_DEST.DESTINATION%TYPE, -- destination <path>
      status             V$ARCHIVE_DEST.STATUS%TYPE,   -- e.g., VALID/INACTIVE 
      min_archive_gen    NUMBER         -- min free space needed for archivelogs
                                        -- to be generated during upgrade
    );

    TYPE systemresource_t IS RECORD (
        tablespaces       tablespaces_t,
        archivelogs       archivelogs_t,
        flashbacklogs     flashbacklogs_t,
        rollback_segments rollback_segments_t,
        flashback_info    flashback_info_t,
        fra_info          fra_info_t,
        archivedest_info  archiveDest_info_t
    );

-- @@Datatype

    TYPE parameter_xml_record_t IS RECORD (
        name              V$PARAMETER.NAME%TYPE,
        value             V$PARAMETER.VALUE%TYPE,    -- used only when a parameter is being renamed.
        type              V$PARAMETER.TYPE%TYPE,
        isdefault         V$PARAMETER.ISDEFAULT%TYPE,
        is_obsoleted      BOOLEAN,
        is_deprecated     BOOLEAN,
        renamed_to_name   VARCHAR2(80),
        new_value         VARCHAR2(80),
        min_value         INTEGER,
        min_char_value    VARCHAR2(20)   -- used for COMPATIBLE whose value is a pseudo number
    );

    TYPE parameters_t IS TABLE OF parameter_xml_record_t INDEX BY BINARY_INTEGER;

    TYPE initparams_t IS RECORD (
        update_params     parameters_t,
        nonhandled_params parameters_t,    -- at 12.2, will have no params.  maintained for XML compatibility only.
        rename_params     parameters_t,
        remove_params     parameters_t
    );

    TYPE preupgradecheck_t IS RECORD  (
        id          VARCHAR2(30),    -- the CHECK name
        severity    NUMBER,          -- "status" attribute in xml
        -- message   message_t,
        rule        message_t,
        broken_rule message_t,
        action      message_t,
        detail      detail_t,
        fixup       fixup_t
    );

    TYPE preupgradechecks_t IS TABLE OF preupgradecheck_t INDEX BY BINARY_INTEGER;

    TYPE rdbmsup_t IS RECORD (
        xmlns               VARCHAR2(1000),
        version             VARCHAR2(30),
        upgradable_versions VARCHAR2(1000)
    );

    TYPE database_t IS RECORD (
        name          VARCHAR2(256),
        containerName VARCHAR2(256),
        containerId   NUMBER,
        version       VARCHAR2(30),
        compatibility VARCHAR2(30),
        blocksize     INTEGER,
        platform      VARCHAR2(100),
        timezoneVer   NUMBER,
        log_mode      VARCHAR2(30),
        readonly      BOOLEAN,
        edition_val   VARCHAR2(30)     -- SYS.REGISTRY$.EDITION%TYPE - except it is not avail on 10.2
    );

    -- this table holds computation info for the memory pools we are
    -- making sizing recommendations for
    TYPE memparameter_record_t IS RECORD (
      name       V$PARAMETER.NAME%TYPE,
      old_value  NUMBER,  -- current value
      min_value  NUMBER,  -- minimum value for upgrade
      new_value  NUMBER,  -- new/recommended value for upgrade
      dif_value  NUMBER,  -- diff of old_value - min_value
      isdefault  V$PARAMETER.ISDEFAULT%TYPE, -- is the value defaulted?
                                             -- 'TRUE'/'FALSE'
      display    BOOLEAN  -- display recommended value? T/F
    );
    TYPE memparameter_table_t IS TABLE of memparameter_record_t
      INDEX BY V$PARAMETER.NAME%TYPE;
    mem_parameters  memparameter_table_t;  -- MEMory PARAMETERS table

    db_is_cdb         BOOLEAN; -- is db a cdb? T/F
    db_is_root        BOOLEAN; -- is db a ROOT container database? T/F
    db_n_pdbs         NUMBER;  -- total Number of PDBs as queried from v$pdbs
    is_show_mem_sizes BOOLEAN := FALSE; -- SHOW/display minimum MEMory SIZES?
                                        -- init to FALSE
    is_archivelog_in_fra BOOLEAN := FALSE; -- are archive logs in FRA? T/F
    is_apex_will_be_upgraded BOOLEAN := FALSE; -- will apex be upgraded? T/F

    --
    --    Provide mappings from a c_check_level_* constant to its string evuivalent used
    --    for XML output only.  These strings have specific meanings to DBUA.  Do not
    --    change without corresponding change in the upgrade.xsd and DBUA buy-in.
    --    IMPORTANT: The order of these strings must correspond to the constants C_CHECK_LEVEL_*
    --
    check_level_strings string_array_t := new string_array_t('SUCCESS','WARNING','INFO','ERROR','RECOMMEND');
    TYPE check_level_ints_t IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
    check_level_ints check_level_ints_t;


    --
    --    PACKAGE Procedures and Functions
    --    The actual CHECK functions will appear later.
    --
    FUNCTION get_con_id  RETURN NUMBER;      -- get container or db id
    FUNCTION get_con_name  RETURN VARCHAR2;  -- get container or db name
    FUNCTION pvalue_to_number (value_string VARCHAR2) RETURN NUMBER;

    FUNCTION get_failed_check_xml(check_name IN VARCHAR2,
                                  substitution_parameter_values IN string_array_t,
                                  detail_type IN VARCHAR2,
                                  detail_info IN VARCHAR2)
                                  RETURN VARCHAR2;
    FUNCTION xml_to_text(xml CLOB) RETURN CLOB;
    FUNCTION run_fixup(check_name VARCHAR2) RETURN BOOLEAN;
    PROCEDURE run_fixup_and_report (check_name VARCHAR2);  -- backwards compatibility
    FUNCTION get_invalid_objects(fromsys IN VARCHAR2) RETURN SYS_REFCURSOR;
    PROCEDURE invalid_objects;
    PROCEDURE init_mem_sizes(memvp IN OUT MEMPARAMETER_TABLE_T);
    PROCEDURE find_mem_sizes(memvp                 IN OUT MEMPARAMETER_TABLE_T,
                             display_min_mem_sizes IN OUT BOOLEAN);
    PROCEDURE find_sga_mem_values(memvp IN OUT MEMPARAMETER_TABLE_T);
    FUNCTION  get_npdbs RETURN NUMBER;
    FUNCTION  is_con_root RETURN BOOLEAN;
    FUNCTION  is_size_this_memparam (name V$PARAMETER.NAME%TYPE) RETURN BOOLEAN;
    PROCEDURE find_archive_dest_info;
    PROCEDURE find_recovery_area_info;
    FUNCTION  find_all_pdb_archive_size RETURN NUMBER;

    --
    --    The CHECK functions
    -- 
    FUNCTION run_preupgrade(output_filename IN VARCHAR2 DEFAULT null,
                        xml IN BOOLEAN DEFAULT false) RETURN BOOLEAN;

    FUNCTION run_all_checks(result_xml OUT CLOB) RETURN NUMBER;

    FUNCTION run_check(check_name IN VARCHAR2, result_xml OUT VARCHAR2) RETURN BOOLEAN;

    FUNCTION oracle_reserved_users_check    (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION supported_version_check        (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION compatible_parameter_check     (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION ols_sys_move_check             (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION awr_dbids_present_check        (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION pa_profile_check               (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION em_present_check               (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION files_need_recovery_check      (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION files_backup_mode_check        (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION two_pc_txn_exist_check         (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION sync_standby_db_check          (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION ultrasearch_data_check         (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION remote_redo_check              (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION sys_default_tablespace_check   (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION sys_default_tablespace_fixup   (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION invalid_laf_check              (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION depend_usr_tables_check        (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION depend_usr_tables_fixup        (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;    
    FUNCTION invalid_usr_tabledata_fixup    (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;    
    FUNCTION invalid_usr_tabledata_check    (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION invalid_sys_tabledata_check    (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION invalid_sys_tabledata_fixup    (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION enabled_indexes_tbl_check      (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION enabled_indexes_tbl_fixup      (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION ordimageindex_check            (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION invalid_objects_exist_check    (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION amd_exists_check               (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION exf_rul_exists_check           (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION new_time_zones_exist_check     (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION old_time_zones_exist_check     (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION purge_recyclebin_check         (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION purge_recyclebin_fixup         (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION job_queue_process_check        (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION job_queue_process_0_check      (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION upg_by_std_upgrd_check         (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION open_cursors_check             (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION xbrl_version_check             (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION apex_patch_check               (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION apex_upgrade_msg_check         (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION default_resource_limit_check   (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION conc_res_mgr_check             (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION conc_res_mgr_fixup             (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;    
    FUNCTION dictionary_stats_check         (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION dictionary_stats_fixup         (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION hidden_params_check            (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION underscore_events_check        (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION audit_records_check            (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION fixed_objects_check            (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION post_dictionary_check          (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION post_dictionary_fixup          (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION compatible_not_set_check       (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION overlap_network_acl_check      (result_txt OUT VARCHAR2) RETURN number;
    FUNCTION repcat_setup_check             (result_txt OUT VARCHAR2) RETURN number;
    FUNCTION ols_version_check              (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION uniaud_tab_check               (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION jvm_mitigation_patch_check     (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION jvm_mitigation_patch_fixup     (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION post_jvm_mitigat_patch_check   (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION audtab_enc_ts_check            (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION trgowner_no_admndbtrg_check    (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION xdb_resource_type_check        (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION network_acl_priv_check         (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION rlp_param_check                (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION mv_refresh_check               (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION dbms_stats_method_opt_check    (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION case_insensitive_auth_check    (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION exclusive_mode_auth_check      (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION data_mining_object_check       (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION pending_dst_session_check      (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION min_archive_dest_size_check    (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION min_recovery_area_size_check   (result_txt OUT VARCHAR2) RETURN NUMBER;
    FUNCTION tempts_notempfile_check        (result_txt OUT VARCHAR2) RETURN NUMBER;
    Function run_int_proc                   (statement VARCHAR2, result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN BOOLEAN;
    --
    --    ##NEW_CHECK## declare the new CHECK function above.  For cleanliness,
    --    please ensure that the order of CHECKs matches the order in preupgrade_messages.properties
    --    though there is no technical requirement to do that here.
    --
   
END dbms_preup;
/

show errors;

-- ***********************************************************************
--                         Package Body
-- ***********************************************************************
CREATE OR REPLACE PACKAGE BODY dbms_preup AS


--
--    Package Body Constants
--
C_TERMINAL_WIDTH NUMBER := 80;
C_FIXUP_TAG VARCHAR2(20) := '(AUTOFIXUP)';

c_kb           CONSTANT BINARY_INTEGER := 1024;       -- 1 KB
c_mb           CONSTANT number := 1048576;    -- 1 MB
c_gb           CONSTANT number := 1073741824; -- 1 GB

-- minimum size constants for tablespace sizing, in units of Kbytes and Mbytes
-- c_sysaux_minsz_kb : (500*1024)Kb = 500Mb -- minimum size for sysaux
-- c_undo_minsz_kb : (400*1024)Kb = 400Mb   -- minimum size for undo
-- c_incby_minsz_mb : 50Mb                  -- minimum size to increase by
c_sysaux_minsz_kb CONSTANT BINARY_INTEGER := 500 * c_kb;  -- (500*1024)kb =500M
c_undo_minsz_kb   CONSTANT BINARY_INTEGER := 400 * c_kb;  -- (400*1024)kb =400M
c_temp_minsz_kb CONSTANT BINARY_INTEGER := 125 * c_kb; -- (125*1024)kb =125M

C_MAX_CHECK_NAME_LENGTH CONSTANT NUMBER := 24;    -- length of function names is 30, but leave 6 characters for our suffixes
C_MSG_NA_B4_121 CONSTANT VARCHAR2(100) := 'Not Applicable in Pre-12.1 database';

--
-- Can't use this for declaring strings but can for length
-- checks
--
c_str_max                CONSTANT NUMBER := 4000;


catalog CONSTANT BINARY_INTEGER:=1;
catproc CONSTANT BINARY_INTEGER:=2;
javavm  CONSTANT BINARY_INTEGER:=3;
xml     CONSTANT BINARY_INTEGER:=4;
rac     CONSTANT BINARY_INTEGER:=5;
owm     CONSTANT BINARY_INTEGER:=6;
mgw     CONSTANT BINARY_INTEGER:=7;
aps     CONSTANT BINARY_INTEGER:=8;
ols     CONSTANT BINARY_INTEGER:=9;
dv      CONSTANT BINARY_INTEGER:=10;
em      CONSTANT BINARY_INTEGER:=11;
context CONSTANT BINARY_INTEGER:=12;
xdb     CONSTANT BINARY_INTEGER:=13;
catjava CONSTANT BINARY_INTEGER:=14;
ordim   CONSTANT BINARY_INTEGER:=15;
sdo     CONSTANT BINARY_INTEGER:=16;
odm     CONSTANT BINARY_INTEGER:=17;
wk      CONSTANT BINARY_INTEGER:=18;
exf     CONSTANT BINARY_INTEGER:=19;
rul     CONSTANT BINARY_INTEGER:=20;
apex    CONSTANT BINARY_INTEGER:=21;
xoq     CONSTANT BINARY_INTEGER:=22;
misc    CONSTANT BINARY_INTEGER:=23;    -- must be last component.

max_components_less_misc BINARY_INTEGER;

--
--    Types
--

--
--    check_record_t holds all of the information about a CHECK
--
TYPE check_record_t IS RECORD (
                       name                VARCHAR2(24),  -- size is 24 because
                                                          -- function names
                                                          -- limited to 30,
                                                          -- less 6 for suffix
                                                          -- like "_check"
                       severity             NUMBER,
                       rule                 VARCHAR2(4000),
                       broken_rule          VARCHAR2(4000),
                       action               VARCHAR2(4000),
                       fixup_stage          VARCHAR2(40),
                       auto_fixup_available BOOLEAN,
                       min_version          VARCHAR2(20),
                       max_version          VARCHAR2(20)
);


--
--    Holds all the static data about the whole set of CHECKs
--
TYPE check_table_t
    IS TABLE OF check_record_t INDEX BY BINARY_INTEGER;

--
--    add a means of easily accessing check_table_t by VARCHAR2
--    as well as by BINARY_INTEGER
--
TYPE check_table_index_t
    IS TABLE OF BINARY_INTEGER INDEX BY VARCHAR2(4000);

TYPE comp_record_t IS RECORD (
  cid            VARCHAR2(30), -- component id
  cname          VARCHAR2(45), -- component name
  version        VARCHAR2(30), -- version
  status         VARCHAR2(15), -- component status
  schema         VARCHAR2(30), -- owner of component
  def_ts         VARCHAR2(30), -- name of default tablespace
  script         VARCHAR2(128), -- upgrade script name
  processed      BOOLEAN,       -- TRUE IF in the registry AND is not
                                -- status REMOVING/REMOVED, OR
                                -- TRUE IF will be in the registry because
                                -- because cmp_info().install is TRUE
  install             BOOLEAN,  -- TRUE if component to be installed in upgrade
  sys_kbytes          INTEGER,  -- upgrade size needed in system tablespace
  sysaux_kbytes       INTEGER,  -- upgrade size needed in sysaux tablespace
  def_ts_kbytes       INTEGER,  -- upgrade size needed in 'other' tablespace
  ins_sys_kbytes      INTEGER,  -- install size needed in system tablespace
  ins_def_kbytes      INTEGER,  -- install size needed in 'other' tablespace
  archivelog_kbytes   INTEGER,  -- minimum archive log space per component
  flashbacklog_kbytes INTEGER,  -- minimum flashback log size per component
  pdb_archivelog_kb   INTEGER   -- minimum archive log per component per pdb
);

TYPE comp_table_t IS TABLE of comp_record_t INDEX BY BINARY_INTEGER;
cmp_info comp_table_t;      -- Table of component information


TYPE tablespace_record_t IS RECORD (
  name    VARCHAR2(128), -- tablespace name
  inuse   INTEGER,       -- kbytes inuse in tablespace
  alloc   INTEGER,       -- kbytes allocated to tbs
  auto    INTEGER,       -- autoextend kbytes available
  avail   INTEGER,       -- total kbytes available
  delta   INTEGER,       -- kbytes required for upgrade
  inc_by  INTEGER,       -- kbytes to increase tablespace by
  min     INTEGER,       -- minimum required kbytes to perform upgrade
  addl    INTEGER,       -- additional space allocated during upgrade
  fname   VARCHAR2(513), -- filename in tablespace
  fauto   BOOLEAN,       -- TRUE if there is a file to increase autoextend
  temporary BOOLEAN,     -- TRUE if Temporary tablespace
  localmanaged BOOLEAN,
  contents SYS.dba_tablespaces.contents%type
);

TYPE tablespace_table_t IS TABLE OF tablespace_record_t
   INDEX BY BINARY_INTEGER;

ts_info tablespace_table_t; -- Tablespace information

TYPE rollback_record_t IS RECORD (
  tbs_name VARCHAR2(30), -- tablespace name
  seg_name VARCHAR2(30), -- segment name
  status   VARCHAR(30),  -- online or offline
  inuse    INTEGER, -- kbytes in use
  next     INTEGER, -- kbytes in NEXT
  max_ext  INTEGER, -- max extents
  auto     INTEGER  -- autoextend available for tablespace
);

TYPE rollback_table_t IS TABLE of rollback_record_t
  INDEX BY BINARY_INTEGER;

rs_info    rollback_table_t;  -- Rollback segment information

TYPE fb_record_t IS RECORD (
  active         BOOLEAN,                    -- ON or OFF
  file_dest      SYS.V$PARAMETER.VALUE%TYPE, -- db_recovery_file_dest
  dsize          INTEGER,                    -- db_recovery_file_dest_size
  name           SYS.V$PARAMETER.VALUE%TYPE, -- name
  limit          INTEGER,                    -- space limit
  used           INTEGER,                    -- Used
  reclaimable    INTEGER,
  files          INTEGER                     -- number of files
);
flashback_info fb_record_t;

fra_info          fra_info_t;          -- stores fra destination
archivedest_info  archiveDest_info_t;  -- stores non-fra archive destination

TYPE parameter_record_t IS RECORD (
    name              V$PARAMETER.NAME%TYPE,
    value             V$PARAMETER.VALUE%TYPE,
    type              V$PARAMETER.TYPE%TYPE,
    isdefault         V$PARAMETER.ISDEFAULT%TYPE,    -- 'FALSE' when the low version db explicitly sets it to non-default value
    isspecified       V$SPPARAMETER.ISSPECIFIED%TYPE, -- Indicates whether the parameter was specified in the spfile (TRUE) or not (FALSE)
    is_obsoleted      BOOLEAN,
    is_deprecated     BOOLEAN,
    renamed_to_name   VARCHAR2(80),
    new_value         V$PARAMETER.VALUE%TYPE,
    min_value         INTEGER
);
TYPE parameter_t IS TABLE OF parameter_record_t INDEX BY V$PARAMETER.NAME%TYPE;
all_parameters parameter_t;

TYPE cursor_t  IS REF CURSOR;

--
--    Convenient table that maps numeric severities to their string meanings
--
TYPE severity_names_t
    IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;

TYPE hash_map_t
    IS TABLE OF VARCHAR2(32767) INDEX BY VARCHAR2(4000);

--
--    "Unchanging" VARIABLES - no changes to these once initialized.
--
C_ORACLE_HIGH_VERSION_4_DOTS VARCHAR2(30);    -- derived from dbms_registry_basic

check_table                  check_table_t;
check_table_index_by_name    check_table_index_t;
severity_names               severity_names_t;

db_name             V$DATABASE.NAME%TYPE;
db_version_4_dots   V$INSTANCE.VERSION%TYPE;    -- Complete version of the un-upgraded database.
db_version_3_dots   V$INSTANCE.VERSION%TYPE;    -- Converted version of the un-upgraded database.
db_version_2_dots   V$INSTANCE.VERSION%TYPE;    -- Converted version of the un-upgraded database.
db_version_1_dot    V$INSTANCE.VERSION%TYPE;    -- Converted version of the un-upgraded database.
db_version_0_dots   V$INSTANCE.VERSION%TYPE;    -- Converted version of the un-upgraded database.
db_compatible       V$PARAMETER.VALUE%TYPE;     -- COMPATIBILITY parameter setting
db_block_size       V$PARAMETER.VALUE%TYPE;     -- DB_BLOCK_SIZE parameter setting
db_undo             V$PARAMETER.VALUE%TYPE;     -- UNDO_MANAGEMENT parameter setting
db_undo_tbs         V$PARAMETER.VALUE%TYPE;     -- UNDO_TABLESPACE parameter setting
db_cpus             NUMBER;  -- # of cpus on the system
db_cpu_threads      NUMBER;
db_64bit            BOOLEAN;
db_32bit            BOOLEAN;
db_platform         VARCHAR2(128);
db_platform_id      NUMBER;
db_tz_version       NUMBER;                     -- timzone number
db_edition          VARCHAR2(30);               -- SYS.REGISTRY$.EDITION%TYPE but not avail on 10.2
db_log_mode         VARCHAR2(30);
db_flashback_on     BOOLEAN;  -- is db flashback on? T/F
db_fra_set          BOOLEAN;  -- is fast recovery area/FRA set? T/F
                              -- TRUE if db_recovery_file_destination and
                              -- db_recovery_file_destination_size are set. 
db_is_XE            BOOLEAN;
db_VLM_enabled      BOOLEAN;
db_inplace_upgrade  BOOLEAN;
db_is_readonly      BOOLEAN;
--db_is_cdb           BOOLEAN;
con_name            VARCHAR(256);
con_id              NUMBER;
cdb_constraint      VARCHAR2(1000);
preupgrade_dir_path VARCHAR2(600);
high_version_apex   VARCHAR2(40) := '&C_APEX_VERSION_4_DOTS';


pMinFlashbackLogGen INTEGER; -- minimum flashback log size estimated to be
                             -- generated during upgrade. in Kbytes.
pMinArchiveLogGen   INTEGER; -- minimum archive log size estimated to be
                             -- generated during upgrade.  in Kbytes.

crlf VARCHAR2(2);    -- will be either a linefeed or a carriage return/linefeed depending on platform

--
--    short lifespan values used during the package_body's initialization only
--    usually just to receive the value of some SELECT before it gets manipulated
--    and stuffed into some permanent global.
--
edition_str      VARCHAR2(30);            -- SYS.REGISTRY$.EDITION%TYPE is not avail on 10.2
param_as_string  V$PARAMETER.VALUE%TYPE;  -- receive v$parameter.value
flashback_off    INTEGER;
cdb_string       VARCHAR2(50);
use_indirect_data_buffers SYS.V$PARAMETER.VALUE%TYPE;
tmp_number       NUMBER;                  -- temp storage to hold number values

--
--    For reading preupgrade_messages.properties
--
props_file utl_file.file_type;
props_line VARCHAR2(32767);
property_name VARCHAR2(4000);
property_value VARCHAR2(32767);
equals_index NUMBER;
properties hash_map_t;
ordered_check_names string_array_collection_t;
check_name VARCHAR2(4000);
check_auto_fixup_available BOOLEAN;
check_subproperty VARCHAR2(4000);
invalid_xml_message message_t;

-- ***********************************************************************
--                  Generic Utility / Helper FUNCTIONs/PROCEDUREs
-- ***********************************************************************

FUNCTION boolean_string(bool BOOLEAN, trueResult VARCHAR2, falseResult VARCHAR2) RETURN VARCHAR2
IS
BEGIN
    IF bool THEN
        RETURN trueResult;
    ELSE
        RETURN falseResult;
    END IF;
END boolean_string;

FUNCTION boolean_string(bool BOOLEAN) RETURN VARCHAR2
IS
BEGIN
    RETURN boolean_string(bool, 'TRUE', 'FALSE');
END boolean_string;


FUNCTION fit_to_terminal(str VARCHAR2, width NUMBER) RETURN VARCHAR2
IS
    idx NUMBER;
BEGIN
    IF (str IS NULL) OR (length(str) <= width) THEN
        RETURN str;
    ELSE
        idx := width;
        WHILE idx > 0 LOOP
            IF substr(str, idx, 1) = ' ' THEN
                RETURN substr(str, 1, idx-1) || crlf || fit_to_terminal(substr(str,idx+1), width);
            END IF;
            idx := idx - 1;
        END LOOP;
        -- if we didn't find a space, we gotta break the line at full width.
        -- note its std to not write to last character on line if that char may be a CR
        -- since some terminals don't handle that well.
        RETURN substr(str, 1, width-1) || crlf || fit_to_terminal(substr(str,width), width);
    END IF;
END fit_to_terminal;

PROCEDURE internal_error(message VARCHAR2)
IS
BEGIN
    --
    --    Preupgrade encountered and unexpected serious error
    --    that will prevent processing downstream.
    --    Emit message directly to output, now, just in case
    --    the exception mechanism gets sick too.
    --
    dbms_output.put_line(properties('INTERNAL_ERROR') || message);

    EXECUTE IMMEDIATE 'BEGIN ' ||
                ' RAISE_APPLICATION_ERROR (-20000, ''' || message || '''); END;';

END internal_error;


PROCEDURE errormsg(message VARCHAR2)
IS
BEGIN
    dbms_output.put_line(message);    -- this function will be expanded in future.
END errormsg;


FUNCTION smart_pad(src VARCHAR2, pad_width_incl_prefix NUMBER, prefix VARCHAR2) RETURN VARCHAR2
IS
   cut_index NUMBER;
   virtual_width NUMBER;  -- since prefix is added to each line, this is width of line ignoring the prefix.
BEGIN
    IF (src IS NULL) THEN
        return null;
    END IF;

    virtual_width := pad_width_incl_prefix - length(prefix);

    --
    --    If the source string contains a CRLF prior to the virtual width,
    --    then respect it.
    --
    cut_index := instr(src, crlf);
    IF ((cut_index > 0) AND
        (cut_index < virtual_width) ) THEN
        RETURN prefix || substr(src, 1, cut_index-1) || crlf ||
               smart_pad(substr(src, cut_index+1), pad_width_incl_prefix, prefix);
    ELSE
        IF length(src) <= virtual_width THEN
            RETURN prefix || src;
        ELSE
            --
            --    SRC is longer than virtual_width and it has no
            --    crlf before the virtual_width.  So, attempt
            --    to chop the SRC at the last space character
            --    before the virtual_width.
            --
            cut_index := virtual_width;
            WHILE ((cut_index > 0) AND
                   (substr(src, cut_index, 1) <> ' ') ) LOOP
                cut_index := cut_index - 1;
            END LOOP;

            IF (cut_index = 0) THEN
                --
                --    SPECIAL CASE: no space or crlf in entire line.  Forced to chop it off "mid-word"
                --    use all characters on the line.
                --
                RETURN prefix || substr(src, 1, virtual_width) || crlf ||
                       smart_pad(substr(src, virtual_width+1), pad_width_incl_prefix, prefix);
            ELSE
                -- the normal chop point.  We found a space character.
                RETURN prefix || substr(src, 1, cut_index-1) || crlf ||
                       smart_pad(substr(src, cut_index+1), pad_width_incl_prefix, prefix);
            END IF;
        END IF;
    END IF;
END smart_pad;

FUNCTION column_format(column_sizes number_array_t, column_values string_array_t) RETURN VARCHAR2
IS
    column_num NUMBER;
    width NUMBER;
    value VARCHAR2(4000);
    result VARCHAR2(32767);

BEGIN
    FOR column_num IN 1 .. column_sizes.count LOOP
        width := column_sizes(column_num);
        value := column_values(column_num);
        IF value IS NULL THEN
            value := ' ';   -- since any column width is non zero, this will
                            -- prevent the *pad routines below from treating null unusually.
        END IF;

        IF width > 0 THEN
            -- use string padding (pad on right)
            value := rpad(value, width);
        ELSE
            -- use numeric padding (pad on the left)
            value := lpad(value, -width);
        END IF;

        result := result || value;
    END LOOP;

    RETURN result;
END column_format;

FUNCTION displayBytes(bytes INTEGER) RETURN VARCHAR2
IS
    metric string_array_t := new string_array_t(' Bytes',' KB',' MB',' GB',' TB');
    thousands NUMBER := 1;
    result VARCHAR2(30) := '';
    local_bytes INTEGER;
BEGIN
    local_bytes := bytes;
    IF local_bytes < 0 THEN
        local_bytes := -local_bytes;
        result := '-';
    END IF;

    -- using 10000 as the cutoff prevents a loss of significant digits.
    -- for example, results may read as high as 9999MB before kicking to 10GB
    WHILE local_bytes >= 10000 LOOP
        thousands := thousands + 1;
        local_bytes := local_bytes / 1024;
    END LOOP;

    RETURN result || to_char(local_bytes) || metric(thousands);
END displayBytes;

--
--    Debugging info output
--
PROCEDURE DisplayDiagLine (line IN VARCHAR2)
IS
BEGIN
    dbms_output.put_line('<!-- DBG: ' || line || ' -->');
END DisplayDiagLine;


--
--    This function converts a parameter string to a number. The function takes
--    into account that the parameter string may have a 'K' or 'M' multiplier
--    character.
--
FUNCTION pvalue_to_number (value_string VARCHAR2) RETURN NUMBER
IS
  ilen NUMBER;
  pvalue_number NUMBER;

BEGIN
    -- How long is the input string?
    ilen := LENGTH ( value_string );

    -- Is there a 'K' or 'M' in last position?
    IF SUBSTR(UPPER(value_string), ilen, 1) = 'K' THEN
         RETURN (c_kb * TO_NUMBER (SUBSTR (value_string, 1, ilen-1)));

    ELSIF SUBSTR(UPPER(value_string), ilen, 1) = 'M' THEN
         RETURN (c_mb * TO_NUMBER (SUBSTR (value_string, 1, ilen-1)));
    END IF;

    -- A multiplier wasn't found. Simply convert this string to a number.
    RETURN (TO_NUMBER (value_string));
END pvalue_to_number;



--  This functions returns a cursor which contains  
--  the invalid objects from the container.
--  if FROMSYS is SYS, the function will return the sys objects
--  otherwise will return non sys objects
FUNCTION get_invalid_objects (FROMSYS IN VARCHAR2)
  RETURN SYS_REFCURSOR
AS
  OBJ_LIST SYS_REFCURSOR;
BEGIN
  IF FROMSYS = 'SYS' THEN
    OPEN OBJ_LIST FOR SELECT OWNER, OBJECT_NAME, OBJECT_TYPE
        FROM SYS.DBA_OBJECTS WHERE STATUS !='VALID' 
        AND OWNER IN ('SYS','SYSTEM')
        ORDER BY OWNER,OBJECT_NAME;
    RETURN OBJ_LIST;
  ELSE
    OPEN OBJ_LIST FOR SELECT OWNER, OBJECT_NAME, OBJECT_TYPE
        FROM SYS.DBA_OBJECTS WHERE STATUS !='VALID' 
        AND OWNER NOT IN ('SYS','SYSTEM')
        ORDER BY OWNER,OBJECT_NAME;
    RETURN OBJ_LIST;
  END IF;
END get_invalid_objects;

--
--  This function shows the SYS/SYSTEM and Non-SYS/SYSTEM
--  invalid objects by one call
--
PROCEDURE invalid_objects
IS
    SYSINV       SYS_REFCURSOR;
    NONSYSINV    SYS_REFCURSOR;
    OWNER        DBA_OBJECTS.OWNER%TYPE;
    OBJECT_NAME  DBA_OBJECTS.OBJECT_NAME%TYPE;
    OBJECT_TYPE  DBA_OBJECTS.OBJECT_TYPE%TYPE;
BEGIN

    DBMS_OUTPUT.PUT_LINE(RPAD('SYS/SYSTEM INVALID OBJECTS', 30));
    DBMS_OUTPUT.PUT_LINE(RPAD('OWNER',30)||RPAD('|OBJECT_NAME',80)||RPAD('|OBJECT_TYPE',19));
    DBMS_OUTPUT.PUT_LINE(RPAD(' ',129,'-'));
    SYSINV := GET_INVALID_OBJECTS('SYS');
    LOOP
        FETCH SYSINV INTO OWNER,OBJECT_NAME,OBJECT_TYPE;
        EXIT WHEN SYSINV%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(RPAD(OWNER,30)||RPAD(OBJECT_NAME,80)||RPAD(OBJECT_TYPE,19));
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(RPAD('NON SYS/SYSTEM INVALID OBJECTS', 30));
    DBMS_OUTPUT.PUT_LINE(RPAD('OWNER',30)||RPAD('|OBJECT_NAME',80)||RPAD('|OBJECT_TYPE',19));
    DBMS_OUTPUT.PUT_LINE(RPAD(' ',129,'-'));
    NONSYSINV := GET_INVALID_OBJECTS('NONSYS');
    LOOP
        FETCH NONSYSINV INTO OWNER,OBJECT_NAME,OBJECT_TYPE;
        EXIT WHEN NONSYSINV%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(RPAD(OWNER,30)||RPAD(OBJECT_NAME,80)||RPAD(OBJECT_TYPE,19));
    END LOOP;
END invalid_objects;

-- Used to execute a sql statement
-- Errors are returned in sqlerrtxt and sqlerrcode
--
FUNCTION execute_sql_statement (statement VARCHAR2,
                                sqlerrtxt OUT VARCHAR2,
                                sqlerrcode OUT NUMBER) RETURN BOOLEAN
IS
BEGIN
    BEGIN
        EXECUTE IMMEDIATE statement;
        EXCEPTION WHEN OTHERS THEN
            sqlerrtxt := SQLERRM;
            sqlerrcode := SQLCODE;
            RETURN false;
    END;
    RETURN true;
END execute_sql_statement;

--
--    Convenience to shorten source code at call sites.
--
PROCEDURE to_file(output_file UTL_FILE.FILE_TYPE, line IN CLOB)
IS
BEGIN
    utl_file.put_line(output_file, line);
END to_file;


--
--    Formats a string with substitution characters for
--    a numbered substitution parameter for a CHECK's messsage.
--
FUNCTION make_msg_param(param_number IN NUMBER) RETURN VARCHAR2
IS
BEGIN
    return C_SUBSTITUTION_DELIMITER_OPEN || to_char(param_number) || C_SUBSTITUTION_DELIMITER_CLOSE;
END make_msg_param;


--
--    get_check_record_by_name
--
FUNCTION get_check_record_by_name(check_name in VARCHAR2) RETURN check_record_t
IS
    result check_record_t := null;
    idx NUMBER := -1;
BEGIN
    IF debug THEN
        dbms_output.put_line('In get_check_record_by_name(), check_name=' || check_name);
    END IF;

    BEGIN
        idx := check_table_index_by_name(check_name);
        result := check_table(idx);
    EXCEPTION
        WHEN OTHERS THEN
            IF debug THEN
                dbms_output.put_line('Unexpected ERROR: could not find CHECK info for ' || check_name);
                dbms_output.put_line('                  idx=' || to_char(idx));
            END IF;
    END;

    RETURN result;
END get_check_record_by_name;


--
--    if db is a cdb, return container name.
--    if db is a noncdb, return container name (which is basically the db name).
--    if db is pre-12.1, then it doesn't have a CON_NAME.  just return db name.
--    note: name returned is in uppercase.
--
FUNCTION get_con_name RETURN VARCHAR2
IS
  conName   VARCHAR2(128) := '';
BEGIN

  -- get container name
  begin
    execute immediate
      'select upper(SYS_CONTEXT(''USERENV'', ''CON_NAME'')) from sys.dual'
      into conName;
  exception
    WHEN e_noParamFound THEN conName := '';
  end;

  -- if container name is null, then this must be a pre-121 db.
  -- just get db name.
  if conName is NULL then
    execute immediate 'select upper(name) from sys.v$database' into conName;
  end if;

  return conName;
END get_con_name;

--
--    if db is a cdb, return container id.
--    if db is a noncdb, return container id (which is 0).
--    if db is pre-12.1, then it doesn't have a CON_ID.  just return 0.
--    note: a noncdb in 12.1 has a con id of 0.
--
FUNCTION get_con_id RETURN NUMBER
IS
  conId   NUMBER := 0;
BEGIN
  begin
    execute immediate
      'select SYS_CONTEXT(''USERENV'', ''CON_ID'') from sys.dual'
      into conId;
  exception
    -- Bug 23539027: Handle the exception when USERENV param is not found
    WHEN e_noParamFound THEN conId:=0;
    WHEN others THEN raise;
  end;

  return conId;
END get_con_id;


PROCEDURE define_check ( name            IN VARCHAR2,
                         severity        IN VARCHAR2,
                         rule            IN VARCHAR2,
                         broken_rule     IN VARCHAR2,
                         action          IN VARCHAR2,
                         fixup_stage     IN VARCHAR2,
                         auto_fixup_available IN BOOLEAN,
                         min_version     IN VARCHAR2,
                         max_version     IN VARCHAR2
                       )
IS
    new_index BINARY_INTEGER;
BEGIN
    IF debug THEN
        dbms_output.put_line('In define_check() for name=' || name);
    END IF;

    new_index := check_table.count() + 1;

    IF (length(name) > C_MAX_CHECK_NAME_LENGTH) THEN
        internal_error('length of ''' || name || ''' is too long for a CHECK name. Max is ' || to_char(C_MAX_CHECK_NAME_LENGTH));
    END IF;

    IF (NOT check_level_ints.exists(severity)) THEN
        internal_error('Invalid value for CHECK.' || name || '.SEVERITY in preupgrade_messages.properties');
    END IF;

    check_table(new_index).name := name;
    check_table(new_index).severity := check_level_ints(severity);
    check_table(new_index).rule := rule;
    check_table(new_index).broken_rule := broken_rule;
    check_table(new_index).action := action;
    check_table(new_index).fixup_stage := fixup_stage;
    check_table(new_index).auto_fixup_available := auto_fixup_available;
    check_table(new_index).min_version := min_version;
    check_table(new_index).max_version := max_version;

    check_table_index_by_name(name) := new_index;
    
END define_check;










--
--    XML related stuff
--

FUNCTION gen_rdbmsup_xml RETURN VARCHAR2
IS
    result varchar2(4000);
BEGIN
    result :=  '<RDBMSUP xmlns="http://www.oracle.com/Upgrade" ' ||
                     'version="' || C_ORACLE_HIGH_VERSION_4_DOTS || '" ' ||
                     'SupportedOracleVersions="&C_UPGRADABLE_VERSIONS">' || crlf;
    IF NOT db_is_cdb THEN
        result := '<Upgrade xmlns="http://www.oracle.com/Upgrade">' || crlf || result;
    END IF;

    RETURN result;

END gen_rdbmsup_xml;

FUNCTION gen_database_xml RETURN VARCHAR2
IS
BEGIN
    -- note: boolean_string() below is case sensitive and requires lower case items to conform to xml boolean standards.
    RETURN '<Database Name="'  || db_name || '" ' ||
             'ContainerName="' || con_name || '" ' ||
             'ContainerId="' || con_id || '" ' ||
             'Version="' || db_version_4_dots || '" ' ||
             'Compatibility="' || db_compatible  || '" ' ||
             'Blocksize="' || db_block_size || '" ' ||
             'Platform="' || db_platform || '" ' ||
             'Timezone="' || to_char(db_tz_version) || '" ' ||
             'LogMode="' || db_log_mode || '" ' ||
             'Readonly="' || boolean_string(db_is_readonly, 'true', 'false') || '" ' ||
             'Edition="' || db_edition || '" ' ||
             '/>' || crlf;
END gen_database_xml;


FUNCTION gen_components_xml RETURN VARCHAR2
IS
    status_attr VARCHAR2(50);
    result VARCHAR2(4000);
BEGIN
    result := '<Components>' || crlf;

    --
    --  By convention, if the user's db is already at the version of this script,
    --  then we need to not emit the body of components so that DBUA knows nothing
    --  is going to be upgraded.
    --
    IF dbms_registry_extended.compare_versions(db_version_4_dots, C_ORACLE_HIGH_VERSION_4_DOTS, 4) <> 0 THEN
      FOR i IN 1 .. max_components_less_misc LOOP
        IF cmp_info(i).processed THEN
          IF (i = catproc) OR (i = wk) THEN
              -- do not process.  catproc is handled as part of catalog below.
              NULL;
          ELSE
              IF (i = catalog) THEN
                IF ((cmp_info(catalog).status = 'VALID' OR
                     cmp_info(catalog).status = 'UPGRADED' ) AND
                    (cmp_info(catproc).status = 'VALID' OR
                     cmp_info(catproc).status = 'UPGRADED' )) THEN
                  status_attr := cmp_info(catalog).status;
                ELSE
                  status_attr := 'INVALID'; 
                END IF;
                result := result || '  <Component id="Oracle Server" type="SERVER" cid="RDBMS" version="'
                  || db_version_4_dots || '" install="' || boolean_string(cmp_info(i).install) || '" status="' || status_attr || '"/>' || crlf;
              ELSE

                IF (cmp_info(i).status IS NULL) THEN
                  -- If we get a NULL value, don't dump out the status
                  status_attr := '';
                ELSE
                  -- Create the status= entry
                  status_attr := ' status="' || cmp_info(i).status || '"';
                END IF;
                result := result || '  <Component id="'   || cmp_info(i).cname   ||
                                  '" cid="'     || cmp_info(i).cid     ||
                                  '" script="'  || cmp_info(i).script  ||
                                  '" version="' || cmp_info(i).version ||
                                  '" install="' || boolean_string(cmp_info(i).install) ||
                                  '"' || status_attr || '/>' || crlf;
              END IF;
          END IF;
        END IF;
      END LOOP;
    END IF;

    result := result || '</Components>' || crlf;

    RETURN result;
END gen_components_xml;


FUNCTION gen_rollback_segs_xml RETURN VARCHAR2
IS
  result VARCHAR2(4000) := '';
BEGIN
    FOR i IN 1..rs_info.count LOOP
      result := result || '  <Rollback_segment name="' || rs_info(i).seg_name ||
                                            '" tablespace="' || rs_info(i).tbs_name ||
                                            '" status="' || rs_info(i).status ||
                                            '" auto="' || rs_info(i).auto ||
                                            '" inuse="' || rs_info(i).inuse*c_kb ||
                                            '" next="' || rs_info(i).next*c_kb ||
                                            '" max_ext="' || rs_info(i).max_ext ||
                          '" />' || crlf;
    END LOOP;

    RETURN result;
END gen_rollback_segs_xml;


FUNCTION gen_flashback_info_xml RETURN VARCHAR2
IS
  min_fra_size number;  -- minimum flashback recovery area size suggested
                        -- for the upgrade
  result VARCHAR2(32767) := '';
BEGIN

  IF pDBGSizeResources THEN
    FOR i in 1..cmp_info.count LOOP
      IF cmp_info(i).processed THEN
        DisplayDiagLine ('Archivelog:   ' || rpad(cmp_info(i).cid,10) || ' ' ||
                         lpad(cmp_info(i).archivelog_kbytes,10));
        DisplayDiagLine ('Flashbacklog: ' || rpad(cmp_info(i).cid,10) || ' ' ||
                lpad(cmp_info(i).flashbacklog_kbytes,10));
      END IF;
    END LOOP;
  END IF;

  IF flashback_info.active THEN

    -- calculate min_fra_size or minimum flashback recovery area size (in Mb)
    -- note: pMinArchiveLogGen and pMinFlashbackLogGen are in Kb
    -- note: the sum of the 2 variables above is saved into min_fra_size
    -- note: so if we divide min_fra_size by c_kb, then min_fra_size is in Mb
    min_fra_size :=
      (pMinArchiveLogGen + pMinFlashbackLogGen) * c_kb;   -- 12.1 used to divide by c_kb to set units MB.

    result := result || '  <Flashback_info name="' || flashback_info.name || '" ' ||
                                          'limit="' || flashback_info.limit || '" ' ||
                                          'used="' || flashback_info.used ||  '" ' ||
                                          'size="' || flashback_info.dsize ||  '" ' ||
                                          'reclaimable="' || flashback_info.reclaimable ||  '" ' ||
                                          'files="' || flashback_info.files || '" ' ||
                                          'min_fra_size="' || min_fra_size || '" />' || crlf;
  END IF;
  RETURN result;
END gen_flashback_info_xml;


-- ARCHIVE/FRA
--  FUNCTION gen_fra_info_xml RETURN VARCHAR2
--  IS
--    result             VARCHAR2(32767) := '';
--  
--  BEGIN
--  
--    IF fra_info.min_fra_size > 0 THEN
--      result := '  <FRA_info name="' || fra_info.name        || '" ' ||
--                'limit="'            || fra_info.limit       || '" ' ||
--                'used="'             || fra_info.used        || '" ' ||
--                'size="'             || fra_info.dsize       || '" ' ||
--                'reclaimable="'      || fra_info.reclaimable || '" ' ||
--                'files="'            || fra_info.files       || '" ' ||
--                'min_archive_gen="'  || fra_info.min_archive_gen   || '" ' ||
--                'min_flashback_gen="'|| fra_info.min_flashback_gen || '" ' ||
--                'min_fra_size="'     || fra_info.min_fra_size      || '" ' ||
--                'additional_size="'  || fra_info.additional_size   || '" ' ||
--                '/>'                 || crlf;
--    END IF;
--  
--    IF debug_archive_fra = TRUE THEN
--      dbms_output.put_line('ARCHIVE/FRA: gen_fra_info_xml: ' || result);
--    END IF;
--  
--    RETURN result;
--  END gen_fra_info_xml;
-- ARCHIVE/FRA


-- ARCHIVE/FRA
--  FUNCTION gen_archivedest_info_xml RETURN VARCHAR2
--  IS
--    result VARCHAR2(32767) := '';
--  BEGIN
--  
--    -- only generate a result string IF archive log size to be generated is > 0
--    -- AND the archive log destination outside of fra is specified
--    IF (archivedest_info.min_archive_gen > 0) AND
--       (archivedest_info.dest_name IS NOT NULL)
--    THEN
--      result := '  <ArchiveDest_info dest_name="' || archivedest_info.dest_name
--                  || '" ' ||
--               'destination="'         || archivedest_info.destination
--                  || '" ' ||
--               'status="'              || archivedest_info.status
--                  || '" ' ||
--               'min_archive_gen="'     || archivedest_info.min_archive_gen
--                  || '" ' ||
--               '/>'                    || crlf;
--    END IF;
--  
--    IF debug_archive_fra = TRUE THEN
--      dbms_output.put_line('ARCHIVE/FRA: gen_archivedest_info_xml: ' || result);
--    END IF;
--  
--    RETURN result;
--  END gen_archivedest_info_xml;
-- ARCHIVE/FRA


FUNCTION gen_systemresource_xml RETURN VARCHAR2
IS
  status_attr VARCHAR2(50);
  result VARCHAR2(32767);

  resourcenum    NUMBER (38);
  changes_req BOOLEAN := FALSE;
BEGIN
    result := '<SystemResource>' || crlf;

    FOR i IN 1..ts_info.count LOOP
      result := result || '  <Tablespace name="' || ts_info(i).name ||
                          '" additional_size="' || TO_CHAR(ROUND(ts_info(i).addl)) ||
                          '" min="' || to_char(ts_info(i).min) ||
                          '" alloc="' || to_char(ts_info(i).alloc) || 
                          '" inc_by="' || to_char(ts_info(i).inc_by) ||
                          '" fauto="' || boolean_string(ts_info(i).fauto) || '"/>' || crlf;
      IF pDBGSizeResources THEN
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                          ' used =                    ' || LPAD(ts_info(i).inuse,10));
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                         ' delta=                    ' || LPAD(ts_info(i).delta,10));
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                         ' total req=                ' || LPAD(ts_info(i).min,10));
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                          ' alloc=                    ' || LPAD(ts_info(i).alloc,10));
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                          ' auto_avail=               ' || LPAD(ts_info(i).auto,10));
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                          ' total avail=              ' ||  LPAD(ts_info(i).avail,10));
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                          ' additional space needed = ' || LPAD(ts_info(i).addl,10));
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                          ' increment by =            ' || LPAD(ts_info(i).inc_by,10));
        DisplayDiagLine(RPAD(ts_info(i).name,10) ||
                          ' total avail=              ' ||  LPAD(ts_info(i).avail,10));
      END IF;
    END LOOP;
    --
    -- ArchiveLogs and Flashback info
    --
    -- bug 18038240:
    -- note: pMinArchiveLogGen and pMinFlashbackLogGen are in Kb
    -- note: DBUA expects these sizes to be in Mb (not Kb)
    -- note: so if we divide these variables by c_kb, then they will be in Mb
    --
    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: pMinArchiveLogGen ' ||
                           pMinArchiveLogGen);
      dbms_output.put_line('ARCHIVE/FRA: pMinFlashbackLogGen ' ||
                           pMinFlashbackLogGen);
    END IF;

    IF db_log_mode = 'ARCHIVELOG' THEN
      resourcenum := ceil(pMinArchiveLogGen / c_kb);  -- display in Mb
    ELSE
      resourcenum := 0;
    END IF;
    result := result || '  <ArchiveLogs name="ArchiveLogs" additional_size="' ||
                                      resourcenum || '" />' || crlf;

    IF db_flashback_on THEN
      resourcenum := ceil(pMinFlashbackLogGen / c_kb);  -- display in Mb
    ELSE
      resourcenum := 0;
    END IF;

    result := result || '  <FlashbackLogs name="FlasbackLogs" additional_size="' ||
                                        resourcenum || '" />' || crlf;

    result := result || gen_rollback_segs_xml;
    result := result || gen_flashback_info_xml;
    -- ARCHIVE/FRA: result := result || gen_fra_info_xml;
    -- ARCHIVE/FRA: result := result || gen_archivedest_info_xml;

    result := result || '</SystemResource>' || crlf;

    RETURN result;
END gen_systemresource_xml;

FUNCTION gen_initparams_xml RETURN VARCHAR2
IS
    result VARCHAR2(32767);
    this_parameter_name SYS.V$PARAMETER.NAME%TYPE;
    this_parameter parameter_record_t;
    dummy_return_string VARCHAR2(4000);    -- used in call to compatible_parameter_check, but its value is throw away
BEGIN
    result := '<InitParams>' || crlf;

    result := result || ' <Update>' || crlf;


    -- do this with a few loops because of previously agreed XML format.
    this_parameter_name := all_parameters.first;
    WHILE this_parameter_name IS NOT NULL LOOP
        this_parameter := all_parameters(this_parameter_name);

        -- 
        --    Check that any minimum values for a numeric parameter are ok.
        --
        --    If the parameter is defaulted in init.ora, then no need to tell
        --    the user about it because they will just accept the new default
        --    in the new release.
        --    ^^^ Exception: For the memory parameters we size for upgrades,
        --    if that memory parameter's current defaulted value is too low
        --    for upgrade, then that parameter and minimum value will be
        --    displayed.
        --
        --    Also note, that renamed parameters have renamed_to_name set and
        --    are not part of this <Update> list.  They're handled below.
        --
        IF ( (is_size_this_memparam(this_parameter.name) = TRUE OR
              this_parameter.isdefault = 'FALSE') AND
             (this_parameter.renamed_to_name IS NULL) ) THEN
            IF this_parameter.type IN (c_param_type_number, c_param_type_number_alt) THEN
                -- a numeric parameter.  Check if its min_value
                IF to_number(this_parameter.value) < this_parameter.min_value THEN
                  result := result || '  <Parameter name="' || this_parameter.name ||
                   '" atleast="' || to_char(this_parameter.min_value) ||
--                   '" atleast_32="' || TO_CHAR(ROUND(this_parameter.min_value32)) ||
--                   '" atleast_64="' || TO_CHAR(ROUND(this_parameter.min_value64)) ||
                   '" type="NUMBER"/>' || crlf;
                END IF;
            ELSIF this_parameter.type = c_param_type_string THEN
                -- string type
                IF this_parameter.new_value IS NOT NULL THEN
                    result := result || '  <Parameter name="' || this_parameter.name ||
                      '" newValue="' || this_parameter.new_value ||
                      '" oldValue="' || this_parameter.value || '" type="STRING"/>' || crlf;
                END IF;
            END IF;
        END IF;
 
        this_parameter_name := all_parameters.next(this_parameter_name);
    END LOOP;

    --  special case "compatible"
    IF compatible_parameter_check(dummy_return_string) <> c_success THEN
      --
      -- Display the minimum compatibility (manual mode has actual check)
      --
      result := result || '  <Parameter name="compatible" atleast="' ||
                '&C_MINIMUM_COMPATIBLE' || '" type="VERSION"/>' || crlf;
    END IF;

    result := result || ' </Update>' || crlf;


    -- The obsolete Migration tag used to go here

    result := result || ' <NonHandled>' || crlf;
    --  '  <Parameter name="remote_listener"/>'
    result := result || ' </NonHandled>' || crlf;


    result := result || ' <Rename>' || crlf;
    this_parameter_name := all_parameters.first;
    WHILE this_parameter_name IS NOT NULL LOOP
        this_parameter := all_parameters(this_parameter_name);

        IF (this_parameter.renamed_to_name IS NOT NULL) AND
           (this_parameter.isdefault = 'FALSE') THEN
            result := result || '  <Parameter name="' || this_parameter.name ||
                        '" newName="' || this_parameter.renamed_to_name || '"';
            IF this_parameter.new_value IS NOT NULL THEN
                result := result || ' newValue="' || this_parameter.new_value || '"';
            END IF;

            result := result || '/>' || crlf;
        END IF;
        this_parameter_name := all_parameters.next(this_parameter_name);
    END LOOP;
    result := result || ' </Rename>' || crlf;



    result := result || ' <Remove>' || crlf;

    this_parameter_name := all_parameters.first;
    WHILE this_parameter_name IS NOT NULL LOOP
        this_parameter := all_parameters(this_parameter_name);

-- Adding the OR condition manage cases when parameter was set at db startup OR parameter had been set in spfile 
        IF (this_parameter.isdefault = 'FALSE' OR this_parameter.isspecified = 'TRUE') THEN
            IF this_parameter.is_obsoleted THEN
                result := result || '  <Parameter name="' || this_parameter.name ||
                                      '" deprecated="FALSE"/>' || crlf;
            ELSIF this_parameter.is_deprecated THEN
                result := result || '  <Parameter name="' || this_parameter.name ||
                                      '" deprecated="TRUE"/>' || crlf;
            END IF;
        END IF;

        this_parameter_name := all_parameters.next(this_parameter_name);
    END LOOP; 

    result := result || ' </Remove>' || crlf ||
                        '</InitParams>' || crlf;
    RETURN result;
END gen_initparams_xml;

-- @@generateXML


--
--    Attribute must match CASE of attr_name and be immediately followed by '='
--
FUNCTION get_xml_attribute(xml IN VARCHAR2,
                           attr_name IN VARCHAR2,
                           default_value IN VARCHAR2,
                           start_index IN NUMBER) RETURN VARCHAR2
IS
    attr_start_index NUMBER;
    attr_end_index NUMBER;
    end_element_start_index NUMBER;
BEGIN
    end_element_start_index := instr(xml, '>', start_index);

    attr_start_index := instr(xml, attr_name||'=', start_index);

    IF (attr_start_index = 0) OR (attr_start_index > end_element_start_index) THEN
        RETURN default_value;
    END IF;

    attr_start_index := instr(xml, '"', attr_start_index)+1;
    attr_end_index := instr(xml, '"', attr_start_index);

    IF debug THEN
        dbms_output.put_line('in get_xml_attribute, attr_start_index=' || attr_start_index || ' attr_end_index=' || attr_end_index);
        dbms_output.put_line('in get_xml_attribute, returning ' || attr_name || '=' ||
            substr(xml, attr_start_index, attr_end_index-attr_start_index));
    END IF;

    RETURN substr(xml, attr_start_index, attr_end_index-attr_start_index);
END get_xml_attribute;

FUNCTION get_xml_element_body(xml IN VARCHAR2,
                      start_index IN NUMBER,
                      end_index IN NUMBER) RETURN VARCHAR2
IS
    body_start_index NUMBER;
    body_end_index NUMBER;
    result VARCHAR2(32767);
BEGIN
    body_start_index := instr(xml, '>', start_index) + 1;
    body_end_index := instr(xml, '<', body_start_index);

    IF debug THEN
        dbms_output.put_line('In get_xml_element_body, the whole element is ''' ||
            substr(xml, start_index, end_index - start_index + 1) || '''');
        dbms_output.put_line('In get_xml_element_body, returning ''' ||
            substr(xml, body_start_index, body_end_index - body_start_index) || '''');
    END IF;


        --
        --    Escape any special characters to be emitted in the XML content, otherwise the XML processing may get sick.
        --    Make sure to perform substitutions in this order, and reverse the order when reading XML back in.
        --

        result := substr(xml, body_start_index, body_end_index - body_start_index);
        result := replace(result, '&' || 'gt;',   '>');
        result := replace(result, '&' || 'lt;',   '<');
        result := replace(result, '&' || 'apos;', '''');
        result := replace(result, '&' || 'quot;', '"');
        result := replace(result, '&' || 'amp;',  '&');

    return result;
END get_xml_element_body;

--
--    returns the name of the next XML element in the xml stream
--    sets the end_of_element_index to the last character thats
--    part of that element.
--    NOTE: This function relies on the CASE of the closing tag
--    matching the case of the opening tag.
--    IF no next element is found, or the XML is not well formed,
--    the function returns NULL and sets end_of_element_index to
--    end_index.
--
FUNCTION identify_next_element(xml IN VARCHAR2,
                               start_index IN NUMBER,
                               end_index IN NUMBER,
                               start_of_element_index OUT NUMBER,
                               end_of_element_index OUT NUMBER) RETURN VARCHAR2
IS
    element_name VARCHAR2(100) := null;
    space_index NUMBER;
    end_opening_tag_index NUMBER;
    end_element_name_index NUMBER;
BEGIN
    IF debug THEN
        dbms_output.put_line('In identify_next_element, start_index=' ||
           to_char(start_index) || ' end_index=' || to_char(end_index));
    END IF;

    start_of_element_index := instr(xml,'<', start_index);
    IF (start_of_element_index = 0) THEN
        start_of_element_index := start_index;   -- if we don't find one, set to "default" start_index
        end_of_element_index := end_index;
        RETURN null;
    END IF;

    end_opening_tag_index := instr(xml, '>', start_of_element_index);
    IF (end_opening_tag_index = 0) THEN
        start_of_element_index := start_index;
        end_of_element_index := end_index;
        RETURN null;
    END IF;

    space_index := instr(xml, ' ', start_of_element_index);
    IF (space_index = 0) THEN
        end_element_name_index := end_opening_tag_index;
    ELSE
        IF (space_index < end_opening_tag_index) THEN
            end_element_name_index := space_index;
        ELSE
            end_element_name_index := end_opening_tag_index;
        END IF;
    END IF;
        
    element_name := substr(xml, start_of_element_index+1,
                                end_element_name_index-start_of_element_index-1);

    IF (substr(xml,end_opening_tag_index-1,1) = '/') THEN
        end_of_element_index := end_opening_tag_index;
    ELSE
        end_of_element_index := instr(xml, '</' || element_name || '>',
                                end_opening_tag_index+1);
        IF (end_of_element_index = 0) THEN
            start_of_element_index := start_index;
            end_of_element_index := end_index;
            RETURN null;
        ELSE
            end_of_element_index := end_of_element_index + length(element_name) + 2;  -- skip "</"
        END IF;
    END IF;

    IF debug THEN
        dbms_output.put_line('  in identify_next_element, returning ''' ||
            element_name || ''' with start_of_element_index=' ||
            to_char(start_of_element_index) ||
            ' and end_of_element_index=' || to_char(end_of_element_index));
    END IF;

    return element_name;
END identify_next_element;



FUNCTION parse_detail_xml(xml IN VARCHAR2,
                          start_index IN NUMBER,
                          end_index IN NUMBER) RETURN detail_t
IS
    result detail_t;
BEGIN
    result.detail_type := get_xml_attribute(xml, 'TYPE', '', start_index);
    result.detail := get_xml_element_body(xml, start_index, end_index);
    return result;
END parse_detail_xml;

FUNCTION parse_fixup_xml(xml IN VARCHAR2,
                          start_index IN NUMBER,
                          end_index IN NUMBER) RETURN fixup_t
IS
    result fixup_t;
BEGIN
    result.fixup_type := get_xml_attribute(xml, 'Type', '', start_index);
    result.fixAtStage := get_xml_attribute(xml, 'FixAtStage', '', start_index);
    RETURN result;
END parse_fixup_xml;

FUNCTION parse_messagevalue_xml(xml IN VARCHAR2,
                               start_index IN NUMBER,
                               end_index IN NUMBER) RETURN messagevalue_t
IS
    result messagevalue_t;
BEGIN
    --
    --    Get the message ID
    --
    result.position := get_xml_attribute(xml, 'Position', 'INVALID_XML', start_index);
    result.value := get_xml_element_body(xml, start_index, end_index);

    RETURN result;
END parse_messagevalue_xml;

FUNCTION parse_message_xml(xml IN VARCHAR2,
                               start_index IN NUMBER,
                               end_index IN NUMBER) RETURN message_t
IS
    result                        message_t;
    next_contained_element        VARCHAR2(100);
    start_of_element_index        NUMBER;
    end_of_element_index          NUMBER;
BEGIN
    --
    --    Get the message ID
    --
    result.id := get_xml_attribute(xml, 'ID', 'INVALID_XML', start_index);


    --
    --    Now parse the text inside the MESSAGE element
    --
    next_contained_element := identify_next_element(xml,
                                  start_index + 1, end_index,
                                  start_of_element_index, end_of_element_index);

    WHILE (next_contained_element IS NOT NULL) LOOP
        next_contained_element := upper(next_contained_element);
        CASE
            WHEN next_contained_element = 'MESSAGEVALUE' THEN
                result.messagevalues(result.messagevalues.count+1) :=
                    parse_messagevalue_xml(xml, start_of_element_index, end_of_element_index);
            ELSE
                IF debug THEN
                    dbms_output.put_line('ERROR in parse_message_xml, invalid next_contained_element=' || next_contained_element);
                END IF;

                RETURN null;
        END CASE;
        next_contained_element := identify_next_element(xml,
                                      end_of_element_index + 1, end_index,
                                      start_of_element_index, end_of_element_index);
    END LOOP;

    RETURN result;

END parse_message_xml;

FUNCTION message_t_to_text(message message_t) RETURN VARCHAR2
IS
    result VARCHAR2(4000);
    this_messagevalue messagevalue_t;
BEGIN
    --
    --    lookup the message.id in the properties file to get its message text.
    --
    BEGIN
        result := properties(message.id);
    EXCEPTION WHEN OTHERS THEN
        internal_error('in message_t_to_text, no text available for message.id=' || message.id);
    END;


    --
    --    Now loop through the messagevalues and perform replacements
    --
    IF debug THEN
        dbms_output.put_line('in message_t_to_text, ' ||
            'total replacements=' || to_char(message.messagevalues.count));
    END IF;

    FOR replacement IN 1 .. message.messagevalues.count LOOP
       this_messagevalue := message.messagevalues(replacement);
       IF debug THEN
           dbms_output.put_line('in message_t_to_text, ' ||
               'this_messagevalue.position=' ||
               to_char(this_messagevalue.position) ||
               ' this_messagevalue.value=' || this_messagevalue.value);
        END IF;

       -- note that the messagevalues may not be in order,
       -- so cannot assume 'replacement = this_messagevalue.position'
       result := replace(result, make_msg_param(this_messagevalue.position),
                                 this_messagevalue.value); 
    END LOOP;     

    --
    --  Perform the allowable html-like replacements of "<br>"
    --
    result := replace(result, '<br>', crlf);

    RETURN result;
END message_t_to_text;


FUNCTION parse_rdbmsup_xml(xml  IN VARCHAR2,
                                   start_index IN NUMBER,
                                   end_index IN NUMBER) RETURN rdbmsup_t
IS
    result rdbmsup_t;
BEGIN
    result.xmlns := get_xml_attribute(xml, 'xmlns', '', start_index);
    result.version := get_xml_attribute(xml, 'version', '', start_index);
    result.upgradable_versions := get_xml_attribute(xml, 'SupportedOracleVersions', '', start_index);

    RETURN result;
END parse_rdbmsup_xml;


FUNCTION parse_database_xml(xml IN VARCHAR2,
                                   start_index IN NUMBER,
                                   end_index IN NUMBER) RETURN database_t
IS
    result database_t;
BEGIN
    result.name := get_xml_attribute(xml, 'Name', '', start_index);
    result.containerName := get_xml_attribute(xml, 'ContainerName', '', start_index);
    result.containerId := get_xml_attribute(xml, 'ContainerId', '', start_index);
    result.version := get_xml_attribute(xml, 'Version', '', start_index);
    result.compatibility := get_xml_attribute(xml, 'Compatibility', '', start_index);
    result.blocksize := get_xml_attribute(xml, 'Blocksize', '', start_index);
    result.platform := get_xml_attribute(xml, 'Platform', '', start_index);
    result.timezoneVer := get_xml_attribute(xml, 'Timezone', '', start_index);
    result.log_mode := get_xml_attribute(xml, 'LogMode', '', start_index);
    result.readonly := (lower(get_xml_attribute(xml, 'Readonly', 'false', start_index)) = 'true');  -- case sensitive
    result.edition_val := get_xml_attribute(xml, 'Edition', '', start_index);

    RETURN result;
END parse_database_xml;

FUNCTION parse_component_xml(xml IN VARCHAR2,
                                   start_index IN NUMBER,
                                   end_index IN NUMBER) RETURN component_t
IS
    result component_t;
BEGIN
    result.cname := get_xml_attribute(xml, 'id', '', start_index);
    result.cid := get_xml_attribute(xml, 'cid', '', start_index);
    result.script := get_xml_attribute(xml, 'script', '', start_index);
    result.version := get_xml_attribute(xml, 'version', '', start_index);
    result.status := get_xml_attribute(xml, 'status', '', start_index);

    RETURN result;
END parse_component_xml;

FUNCTION parse_components_xml(xml IN VARCHAR2,
                                   start_index IN NUMBER,
                                   end_index IN NUMBER) RETURN components_t
IS
    result components_t;
    next_contained_element VARCHAR2(100);
    start_of_element_index NUMBER;
    end_of_element_index NUMBER;
    msg_start_index NUMBER;
    msg_end_index NUMBER;
BEGIN
    --
    --    Initialize result fields.
    --
    next_contained_element := identify_next_element(xml, start_index + 1, end_index,
                                  start_of_element_index, end_of_element_index);
    WHILE (next_contained_element IS NOT NULL) LOOP
        next_contained_element := upper(next_contained_element);
        CASE
            WHEN next_contained_element = 'COMPONENT' THEN
                result(result.count+1) := parse_component_xml(xml, start_of_element_index, end_of_element_index);
            ELSE
                internal_error('invalid internal XML.  Found unexpected element "' || next_contained_element ||
                               '" while parsing <Components>.' ||
                               ' Rerun preupgrade but generate XML output instead of' ||
                               ' text to identify problem for Oracle Support.');
        END CASE;

        next_contained_element := identify_next_element(xml, end_of_element_index+1, end_index, start_of_element_index, end_of_element_index);
    END LOOP;

    RETURN result;
END parse_components_xml;

FUNCTION parse_tablespace_xml(xml IN VARCHAR2,
                              start_index IN NUMBER,
                              end_index IN NUMBER) RETURN tablespace_t
IS
    result tablespace_t;
BEGIN
    result.name := get_xml_attribute(xml, 'name', '', start_index);
    result.additional_size := to_number(get_xml_attribute(xml, 'additional_size', '0', start_index));
    result.min := to_number(get_xml_attribute(xml, 'min', '0', start_index));
    result.alloc := to_number(get_xml_attribute(xml, 'alloc', '0', start_index));
    result.inc_by := to_number(get_xml_attribute(xml, 'inc_by', '0', start_index));
    result.fauto := (upper(get_xml_attribute(xml, 'fauto', 'FALSE', start_index)) = 'TRUE');
    result.contents := get_xml_attribute(xml, 'contents', '', start_index);

    RETURN result;
END parse_tablespace_xml;

FUNCTION parse_archivelogs_xml(xml IN VARCHAR2,
                               start_index IN NUMBER,
                               end_index IN NUMBER) RETURN archivelogs_t
IS
    result archivelogs_t;
BEGIN
    result.name := get_xml_attribute(xml, 'name', '', start_index);
    result.additional_size := to_number(get_xml_attribute(xml, 'additional_size', '0', start_index));

    RETURN result;
END parse_archivelogs_xml;

FUNCTION parse_flashbacklogs_xml(xml IN VARCHAR2,
                                 start_index IN NUMBER,
                                 end_index IN NUMBER) RETURN flashbacklogs_t
IS
    result flashbacklogs_t;
BEGIN
    result.name := get_xml_attribute(xml, 'name', '', start_index);
    result.additional_size := to_number(get_xml_attribute(xml, 'additional_size', '0', start_index));

    RETURN result;
END parse_flashbacklogs_xml;

FUNCTION parse_rollback_segment_xml(xml IN VARCHAR2,
                                 start_index IN NUMBER,
                                 end_index IN NUMBER) RETURN rollback_segment_t
IS
    result rollback_segment_t;
BEGIN
    result.name := get_xml_attribute(xml, 'name', '', start_index);
    result.tablespc := get_xml_attribute(xml, 'tablespace', '', start_index);
    result.status := get_xml_attribute(xml, 'status', '', start_index);
    result.auto := to_number(get_xml_attribute(xml, 'auto', '0', start_index));
    result.inuse := to_number(get_xml_attribute(xml, 'inuse', '0', start_index));
    result.next := to_number(get_xml_attribute(xml, 'next', '0', start_index));
    result.max_ext := to_number(get_xml_attribute(xml, 'max_ext', '0', start_index));

    RETURN result;
END parse_rollback_segment_xml;

FUNCTION parse_flashback_info_xml(xml IN VARCHAR2,
                                 start_index IN NUMBER,
                                 end_index IN NUMBER) RETURN flashback_info_t
IS
    result flashback_info_t;
BEGIN
    result.name := get_xml_attribute(xml, 'name', '', start_index);
    result.limit := get_xml_attribute(xml, 'limit', '0', start_index);
    result.used := get_xml_attribute(xml, 'used', '0', start_index);
    result.dsize := get_xml_attribute(xml, 'size', '0', start_index);
    result.reclaimable := get_xml_attribute(xml, 'reclaimable', '0', start_index);
    result.files := get_xml_attribute(xml, 'files', '0', start_index);
    result.min_fra_size := get_xml_attribute(xml, 'min_fra_size', '0', start_index);

    RETURN result;
END parse_flashback_info_xml;


-- ARCHIVE/FRA
--  FUNCTION parse_fra_info_xml(xml         IN VARCHAR2,
--                              start_index IN NUMBER,
--                              end_index   IN NUMBER)  RETURN fra_info_t
--  IS
--      result fra_info_t;
--  BEGIN
--      result.name  := get_xml_attribute(xml, 'name', '', start_index);
--      result.limit := get_xml_attribute(xml, 'limit', '0', start_index);
--      result.used  := get_xml_attribute(xml, 'used',  '0', start_index);
--      result.dsize := get_xml_attribute(xml, 'size',  '0', start_index);
--      result.reclaimable        := get_xml_attribute(xml, 'reclaimable', '0',
--                                                     start_index);
--      result.files              := get_xml_attribute(xml, 'files', '0',
--                                                     start_index);
--      result.min_archive_gen    := get_xml_attribute(xml, 'min_archive_gen',
--                                                     '0', start_index);
--      result.min_flashback_gen  := get_xml_attribute(xml, 'min_flashback_gen',
--                                                     '0', start_index);
--      result.min_fra_size       := get_xml_attribute(xml, 'min_fra_size', '0',
--                                                     start_index);
--      result.additional_size    := get_xml_attribute(xml, 'additional_size', '0',
--                                                     start_index);
--  
--      RETURN result;
--  END parse_fra_info_xml;


-- ARCHIVE/FRA
--  FUNCTION parse_archivedest_info_xml
--             (xml         IN VARCHAR2,
--              start_index IN NUMBER,
--              end_index   IN NUMBER)    RETURN archiveDest_info_t
--  IS
--    result archiveDest_info_t;
--  BEGIN
--  
--    result.dest_name       := get_xml_attribute(xml, 'dest_name',
--                                                '', start_index);
--    result.destination     := get_xml_attribute(xml, 'destination',
--                                                '', start_index);
--    result.status          := get_xml_attribute(xml, 'status',
--                                                'INACTIVE', start_index);
--    result.min_archive_gen := get_xml_attribute(xml, 'min_archive_gen',
--                                                '0', start_index);
--  
--    RETURN result;
--  END parse_archivedest_info_xml;
-- ARCHIVE/FRA


FUNCTION parse_systemresource_xml(xml IN VARCHAR2,
                                  start_index IN NUMBER,
                                  end_index IN NUMBER) RETURN systemresource_t
IS
    result systemresource_t;
    next_contained_element VARCHAR2(100);
    start_of_element_index NUMBER;
    end_of_element_index NUMBER;
    msg_start_index NUMBER;
    msg_end_index NUMBER;
BEGIN
    --
    --    Initialize result fields.
    --
    next_contained_element := identify_next_element(xml, start_index + 1, end_index,
                                  start_of_element_index, end_of_element_index);
    WHILE (next_contained_element IS NOT NULL) LOOP
        next_contained_element := upper(next_contained_element);
        CASE
            WHEN next_contained_element = 'TABLESPACE' THEN
                result.tablespaces(result.tablespaces.count+1) := parse_tablespace_xml(xml, start_of_element_index, end_of_element_index);
            WHEN next_contained_element = 'ARCHIVELOGS' THEN
                result.archivelogs := parse_archivelogs_xml(xml, start_of_element_index, end_of_element_index);
            WHEN next_contained_element = 'FLASHBACKLOGS' THEN
                result.flashbacklogs := parse_flashbacklogs_xml(xml, start_of_element_index, end_of_element_index);
            WHEN next_contained_element = 'ROLLBACK_SEGMENT' THEN
                result.rollback_segments(result.rollback_segments.count+1) :=
                    parse_rollback_segment_xml(xml, start_of_element_index, end_of_element_index);
            WHEN next_contained_element = 'FLASHBACK_INFO' THEN
                result.flashback_info :=
                    parse_flashback_info_xml(xml, start_of_element_index, end_of_element_index);
-- ARCHIVE/FRA begin-here
--            WHEN next_contained_element = 'FRA_INFO' THEN
--                result.fra_info :=
--                    parse_fra_info_xml(xml, start_of_element_index, end_of_element_index);
--            WHEN next_contained_element = 'ARCHIVEDEST_INFO' THEN
--                result.archivedest_info :=
--                    parse_archivedest_info_xml(xml, start_of_element_index, end_of_element_index);
-- ARCHIVE/FRA end-here
            ELSE
                internal_error('invalid internal XML.  Found unexpected element "' || next_contained_element ||
                               '" while parsing <SystemResource>.' ||
                               ' Rerun preupgrade but generate XML output instead of' ||
                               ' text to identify problem for Oracle Support.');
        END CASE;

        next_contained_element := identify_next_element(xml, end_of_element_index+1, end_index, start_of_element_index, end_of_element_index);
    END LOOP;

    RETURN result;
END parse_systemresource_xml;

-- @@parse
FUNCTION parse_parameter_xml(xml IN VARCHAR2,
                                 start_index IN NUMBER,
                                 end_index IN NUMBER) RETURN parameter_xml_record_t
IS
    result parameter_xml_record_t;
    stringType VARCHAR2(50);
    deprecated VARCHAR2(30);
BEGIN
    result.name := get_xml_attribute(xml, 'name', '', start_index);
    -- result.min_value := to_number(get_xml_attribute(xml, 'atleast', '0', start_index));
    result.isdefault := get_xml_attribute(xml, 'isdefault', '', start_index);
    result.renamed_to_name := get_xml_attribute(xml, 'newName', '', start_index);
    result.new_value := get_xml_attribute(xml, 'newValue', '', start_index);
    result.value := get_xml_attribute(xml, 'oldValue', '', start_index);
    result.min_char_value := null;  -- default.  set below as needed.

    stringType := get_xml_attribute(xml, 'type', '', start_index);
    IF stringType = 'NUMBER' THEN
        result.type := c_param_type_number;
        result.new_value := '';   -- does not apply to NUMBERs this is for a STRING
        result.min_value := to_number(get_xml_attribute(xml, 'atleast', '0', start_index));
    ELSIF stringType = 'STRING' THEN
        result.type := c_param_type_string;
        result.new_value := get_xml_attribute(xml, 'newValue', '', start_index);
    ELSIF stringType = 'VERSION' THEN
        -- this stringType is used for the setting of COMPATIBLE since its value isnt really a number.
        result.type := c_param_type_version;
        result.new_value := get_xml_attribute(xml, 'atleast', '', start_index);
        result.min_char_value := get_xml_attribute(xml, 'atleast', '0', start_index);
    ELSE
        result.type := c_param_type_other;    -- stringType is null or unknown.
        result.new_value := get_xml_attribute(xml, 'newValue', '', start_index);
    END IF;

    deprecated := get_xml_attribute(xml, 'deprecated', '', start_index);
    IF (deprecated = 'TRUE') THEN
        result.is_deprecated := TRUE;
        result.is_obsoleted := FALSE;
    ELSIF (deprecated = 'FALSE') THEN
        result.is_obsoleted := TRUE;
        result.is_deprecated := FALSE;
    ELSE
        result.is_obsoleted := FALSE;
        result.is_deprecated := FALSE;
    END IF;

    RETURN result;
END parse_parameter_xml;

FUNCTION parse_parameters_xml(xml IN VARCHAR2,
                                   start_index IN NUMBER,
                                   end_index IN NUMBER) RETURN parameters_t
IS
    result parameters_t;
    next_contained_element VARCHAR2(100);
    start_of_element_index NUMBER;
    end_of_element_index NUMBER;
    msg_start_index NUMBER;
    msg_end_index NUMBER;
BEGIN
    --
    --    Initialize result fields.
    --
    next_contained_element := identify_next_element(xml, start_index + 1, end_index,
                                  start_of_element_index, end_of_element_index);
    WHILE (next_contained_element IS NOT NULL) LOOP
        next_contained_element := upper(next_contained_element);
        CASE
            WHEN next_contained_element = 'PARAMETER' THEN
                result(result.count+1) :=
                    parse_parameter_xml(xml, start_of_element_index, end_of_element_index);
            ELSE
                internal_error('invalid internal XML.  Found unexpected element "' || next_contained_element ||
                               '" while expecting <Parameter>.' ||
                               ' Rerun preupgrade but generate XML output instead of' ||
                               ' text to identify problem for Oracle Support.');
        END CASE;

        next_contained_element := identify_next_element(xml, end_of_element_index+1, end_index, start_of_element_index, end_of_element_index);
    END LOOP;

    RETURN result;
END parse_parameters_xml;


FUNCTION parse_initparams_xml(xml IN VARCHAR2,
                                   start_index IN NUMBER,
                                   end_index IN NUMBER) RETURN initparams_t
IS
    result initparams_t;
    next_contained_element VARCHAR2(100);
    start_of_element_index NUMBER;
    end_of_element_index NUMBER;
    msg_start_index NUMBER;
    msg_end_index NUMBER;
BEGIN
    --
    --    Initialize result fields.
    --
    next_contained_element := identify_next_element(xml, start_index + 1, end_index,
                                  start_of_element_index, end_of_element_index);
    WHILE (next_contained_element IS NOT NULL) LOOP
        next_contained_element := upper(next_contained_element);
        CASE
            WHEN next_contained_element = 'UPDATE' THEN
                result.update_params :=
                    parse_parameters_xml(xml, start_of_element_index, end_of_element_index);
            WHEN next_contained_element = 'NONHANDLED' THEN
                result.nonhandled_params :=
                    parse_parameters_xml(xml, start_of_element_index, end_of_element_index);
            WHEN next_contained_element = 'RENAME' THEN
                result.rename_params :=
                    parse_parameters_xml(xml, start_of_element_index, end_of_element_index);
            WHEN next_contained_element = 'REMOVE' THEN
                result.remove_params :=
                    parse_parameters_xml(xml, start_of_element_index, end_of_element_index);
            ELSE
                internal_error('invalid internal XML.  Found unexpected element "' || next_contained_element ||
                               '" while parsing <InitParams>.' ||
                               ' Rerun preupgrade but generate XML output instead of' ||
                               ' text to identify problem for Oracle Support.');
        END CASE;

        next_contained_element := identify_next_element(xml, end_of_element_index+1, end_index, start_of_element_index, end_of_element_index);
    END LOOP;

    RETURN result;
END parse_initparams_xml;

FUNCTION parse_preupgradecheck_xml(xml IN VARCHAR2,
                                   start_index IN NUMBER,
                                   end_index IN NUMBER) RETURN preupgradecheck_t
IS
    result preupgradecheck_t;
    next_contained_element VARCHAR2(100);
    start_of_element_index NUMBER;
    end_of_element_index NUMBER;
    msg_start_index NUMBER;
    msg_end_index NUMBER;
    default_status_value VARCHAR2(20);
    status_xml_attribute_value VARCHAR2(100);
BEGIN
    default_status_value := check_level_strings(c_check_level_success);
    status_xml_attribute_value := get_xml_attribute(xml, 'Status', default_status_value, start_index);

    IF debug THEN
        IF (xml IS NULL) THEN
            dbms_output.put_line('In parse_preupgradecheck_xml, XML is NULL');
        END IF;
        dbms_output.put_line('Leading  characters in XML are: ' || substr(xml, start_index-20, 20));
        dbms_output.put_line('Trailing characters in XML are: ' || substr(xml, start_index, 20));
        dbms_output.put_line('default_status_value=' || default_status_value);
        dbms_output.put_line('status_xml_attribute_value=' || status_xml_attribute_value);
        dbms_output.put_line('In parse_preupgradecheck_xml.  Displaying XML text for parsing. start_index=' || start_index ||
                             ' end_index=' || end_index ||
                             ' Length of the whole XML is ' || length(xml));
        dbms_output.put_line(substr(xml,start_index, end_index));
    END IF;


    --
    --    Initialize result fields.
    --
    result.id := get_xml_attribute(xml, 'ID', '', start_index);

    result.severity := check_level_ints(status_xml_attribute_value);
    result.rule := null;
    result.broken_rule := null;
    result.action := null;
    result.fixup := null;

    --
    --    Now parse the text inside the PREUPGRADECHECK element.
    --
    next_contained_element := identify_next_element(xml,
                                  start_index + 1, end_index,
                                  start_of_element_index, end_of_element_index);
    WHILE (next_contained_element IS NOT NULL) LOOP
        next_contained_element := upper(next_contained_element);
        CASE

            WHEN next_contained_element = 'RULE' THEN
                next_contained_element := identify_next_element(xml, start_of_element_index+1,
                                          end_of_element_index, msg_start_index, msg_end_index);
                IF (upper(next_contained_element) = 'MESSAGE') THEN
                    result.rule := parse_message_xml(xml, msg_start_index, msg_end_index);
                ELSE
                    result.rule := invalid_xml_message;
                END IF;

            WHEN next_contained_element = 'BROKEN_RULE' THEN
                next_contained_element := identify_next_element(xml, start_of_element_index+1,
                                          end_of_element_index, msg_start_index, msg_end_index);
                IF (upper(next_contained_element) = 'MESSAGE') THEN
                    result.broken_rule := parse_message_xml(xml, msg_start_index, msg_end_index);
                ELSE
                    result.broken_rule := invalid_xml_message;
                END IF;

            WHEN next_contained_element = 'ACTION' THEN
                next_contained_element := identify_next_element(xml, start_of_element_index+1,
                                          end_of_element_index, msg_start_index, msg_end_index);
                IF (upper(next_contained_element) = 'MESSAGE') THEN
                    result.action := parse_message_xml(xml, msg_start_index, msg_end_index);
                ELSE
                    result.action := invalid_xml_message;
                END IF;

            WHEN next_contained_element = 'DETAIL' THEN
                result.detail := parse_detail_xml(xml, start_of_element_index, end_of_element_index);

            WHEN next_contained_element = 'FIXUP' THEN
                result.fixup := parse_fixup_xml(xml, start_of_element_index, end_of_element_index);

            ELSE
                internal_error('invalid internal XML.  Found unexpected element "' || next_contained_element ||
                               '" while parsing <Preupgradecheck>.' ||
                               ' Rerun preupgrade but generate XML output instead of' ||
                               ' text to identify problem for Oracle Support.');
        END CASE;
        next_contained_element := identify_next_element(xml,
                                      end_of_element_index + 1, end_index,
                                      start_of_element_index, end_of_element_index);
    END LOOP;

    RETURN result;
END parse_preupgradecheck_xml;



FUNCTION parse_preupgradechecks_xml(xml IN VARCHAR2,
                                   start_index IN NUMBER,
                                   end_index IN NUMBER) RETURN preupgradechecks_t
IS
    result preupgradechecks_t;
    next_contained_element VARCHAR2(100);
    start_of_element_index NUMBER;
    end_of_element_index NUMBER;
    msg_start_index NUMBER;
    msg_end_index NUMBER;
BEGIN
    --
    --    Now parse the text inside the PREUPGRADECHECK element.
    --
    next_contained_element := identify_next_element(xml,
                                  start_index + 1, end_index,
                                  start_of_element_index, end_of_element_index);
    WHILE (next_contained_element IS NOT NULL) LOOP
        next_contained_element := upper(next_contained_element);

        IF debug THEN
            dbms_output.put_line('In parse_preupgradechecks.  Got element ' || next_contained_element);
        END IF;

        CASE

            WHEN next_contained_element = 'PREUPGRADECHECK' THEN
--                next_contained_element := identify_next_element(xml, start_of_element_index+1,
--                                          end_of_element_index, msg_start_index, msg_end_index);
--                result(result.count+1) := parse_preupgradecheck_xml(xml, msg_start_index, msg_end_index);
                result(result.count+1) := parse_preupgradecheck_xml(xml, start_of_element_index, end_of_element_index);
            ELSE
                internal_error('invalid internal XML.  Found unexpected element "' || next_contained_element ||
                               '" while parsing <Preupgradechecks>.' ||
                               ' Rerun preupgrade but generate XML output instead of' ||
                               ' text to identify problem for Oracle Support.');
        END CASE;
        next_contained_element := identify_next_element(xml,
                                      end_of_element_index + 1, end_index,
                                      start_of_element_index, end_of_element_index);
    END LOOP;

    RETURN result;
END parse_preupgradechecks_xml;


FUNCTION rdbmsup_t_to_text(rdbmsup rdbmsup_t) RETURN VARCHAR2
IS
BEGIN
    -- do not print out xmlns or upgradable_versions

    RETURN 'Report generated by Oracle Database Pre-Upgrade Information Tool Version ' || rdbmsup.version || crlf ||
           crlf ||
           'Upgrade-To version: ' || rdbmsup.version || crlf ||
           crlf ||
           '=======================================' || crlf ||
           'Status of the database prior to upgrade' || crlf ||
           '=======================================';
END rdbmsup_t_to_text;

FUNCTION database_t_to_text(my_database database_t) RETURN VARCHAR2
IS
    containerNameString VARCHAR2(200);
    containerIdString VARCHAR2(200);
BEGIN
    IF dbms_registry_extended.compare_versions(db_version_4_dots, '12.1.0.1.0', 4) = -1 THEN
        containerNameString := C_MSG_NA_B4_121;
        containerIdString := C_MSG_NA_B4_121;
    ELSE
        containerNameString := my_database.containerName;
        containerIdString := my_database.containerId;
    END IF;

    RETURN '      Database Name:  ' || my_database.name || crlf ||
           '     Container Name:  ' || containerNameString || crlf ||
           '       Container ID:  ' || containerIdString || crlf ||
           '            Version:  ' || my_database.version || crlf ||
           '         Compatible:  ' || my_database.compatibility || crlf ||
           '          Blocksize:  ' || my_database.blocksize || crlf ||
           '           Platform:  ' || my_database.platform || crlf ||
           '      Timezone File:  ' || my_database.timezoneVer || crlf ||
           '  Database log mode:  ' || my_database.log_mode || crlf ||
           '           Readonly:  ' || boolean_string(my_database.readonly) ||crlf||
           '            Edition:  ' || db_edition;
END database_t_to_text;

FUNCTION preupgradecheck_t_to_text(preupgradecheck preupgradecheck_t) RETURN VARCHAR2
IS
    action_text VARCHAR2(4000);
    rule_text VARCHAR2(4000);
    result VARCHAR2(32767);
BEGIN
    IF debug THEN
        dbms_output.put_line('preupgradecheck.id=' || preupgradecheck.id);
        dbms_output.put_line('preupgradecheck.fixup.fixup_type=' || preupgradecheck.fixup.fixup_type);
        dbms_output.put_line('preupgradecheck.fixup.fixAtStage=' || preupgradecheck.fixup.fixAtStage);
        dbms_output.put_line('preupgradecheck.severity=' || preupgradecheck.severity);
    END IF;

    action_text := message_t_to_text(preupgradecheck.action);
    --
    --    put sentence separator after action_text if it does not at end with crlf
    --
    IF substr(action_text, length(action_text)-length(crlf)+1, length(crlf)) <> crlf THEN
        action_text := action_text || '  ';
    END IF;


    rule_text := message_t_to_text(preupgradecheck.rule);
    IF preupgradecheck.fixup.fixup_type = 'AUTOMATIC' THEN
        action_text := C_FIXUP_TAG || ' ' || action_text;
    END IF;

    result := smart_pad(action_text || crlf || crlf ||
                    message_t_to_text(preupgradecheck.broken_rule) || crlf || crlf ||
                    rule_text,
                    78, '     ');
    result := '   + ' || substr(result,6);
    RETURN result;

END preupgradecheck_t_to_text;

FUNCTION preupgradechecks_t_to_text(preupgradechecks preupgradechecks_t, initparams initparams_t) RETURN CLOB
IS
    check_index NUMBER := 1;
    last_index NUMBER;
    previous_index NUMBER;
    displayed_header BOOLEAN;
    result CLOB;
    this_param parameter_xml_record_t;
BEGIN
    last_index := preupgradechecks.count;

    --
    --    REQUIRED ACTIONS are reported, even if none exist, to be clear to user.
    --
    WHILE (check_index <= last_index) AND
          ( (preupgradechecks(check_index).fixup.fixAtStage = 'PRE') OR
            (preupgradechecks(check_index).fixup.fixAtStage = 'VALIDATION') ) AND
          (preupgradechecks(check_index).severity = c_check_level_error) LOOP
        result := result || preupgradecheck_t_to_text(preupgradechecks(check_index)) || crlf || crlf;
        check_index := check_index + 1;
    END LOOP;

    -- IF (check_index = 1) THEN
    --     result := result || '  None' || crlf || crlf;
    -- END IF;

    --
    --    DEPRECATED parameters
    --
    displayed_header := false;

    FOR i IN 1..initparams.remove_params.count LOOP
        this_param := initparams.remove_params(i);
        IF this_param.is_deprecated THEN

            IF NOT displayed_header THEN
                result := result || '  RECOMMENDED ACTIONS' || crlf ||
                                    '  ===================' || crlf;
                result := result ||
                          '   + Consider removing the following DEPRECATED initialization parameters.' || crlf ||
                          '     They are not OBSOLETE in version ' || C_ORACLE_HIGH_VERSION_4_DOTS || crlf ||
                          '     but probably will be OBSOLETE in a future release.' || crlf || crlf ||
                          '     Parameter                      ' || crlf ||
                          '     ------------------------------ ' || crlf;
                displayed_header := true;
            END IF;
            result := result || column_format(new number_array_t(5,30),
                                              new string_array_t('     ',this_param.name) )
                                              || crlf; 
        END IF;
    END LOOP;

    -- put a blank line after the above table if we printed one.
    IF displayed_header THEN
        result := result || crlf;
    END IF;


    WHILE (check_index <= last_index) AND
          ( (preupgradechecks(check_index).fixup.fixAtStage = 'PRE') OR
            (preupgradechecks(check_index).fixup.fixAtStage = 'VALIDATION') ) AND
          ( (preupgradechecks(check_index).severity = c_check_level_warning) OR
            (preupgradechecks(check_index).severity = c_check_level_recommend) ) LOOP
        IF NOT displayed_header THEN
            result := result || '  RECOMMENDED ACTIONS' || crlf ||
                                '  ===================' || crlf;
            displayed_header := true;
        END IF;
        result := result || preupgradecheck_t_to_text(preupgradechecks(check_index)) || crlf || crlf;
        check_index := check_index + 1;
    END LOOP;

    displayed_header := false;

    WHILE (check_index <= last_index) AND
          ( (preupgradechecks(check_index).fixup.fixAtStage = 'PRE') OR
            (preupgradechecks(check_index).fixup.fixAtStage = 'VALIDATION') ) AND
          (preupgradechecks(check_index).severity = c_check_level_info) LOOP
        IF NOT displayed_header THEN
            result := result || '  INFORMATION ONLY' || crlf ||
                                '  ================' || crlf;
            displayed_header := true;
        END IF;
        result := result || preupgradecheck_t_to_text(preupgradechecks(check_index)) || crlf || crlf;
        check_index := check_index + 1;
    END LOOP;

    displayed_header := false;

    result := result ||
              '=============' || crlf ||
              'AFTER UPGRADE' || crlf ||
              '=============' || crlf ||
              crlf ||
              '  Run <preupgradeLogDirPath>/' || C_FIXUP_SCRIPT_NAME_POST || ' to complete all ' || crlf ||
              '  of the AFTER UPGRADE action items below marked with ''' || C_FIXUP_TAG || '''.' || crlf ||
              crlf ||
              '  REQUIRED ACTIONS' || crlf ||
              '  ================' || crlf;
    previous_index := check_index;
    WHILE (check_index <= last_index) AND
          (preupgradechecks(check_index).fixup.fixAtStage = 'POST') AND
          (preupgradechecks(check_index).severity = c_check_level_error) LOOP
        IF NOT displayed_header THEN
            displayed_header := true;
        END IF;
        result := result || preupgradecheck_t_to_text(preupgradechecks(check_index)) || crlf || crlf;
        check_index := check_index + 1;
    END LOOP;

    IF (check_index = previous_index) THEN
        result := result || '  None' || crlf || crlf;
    END IF;

    displayed_header := false;

    WHILE (check_index <= last_index) AND
          (preupgradechecks(check_index).fixup.fixAtStage = 'POST') AND
          ( (preupgradechecks(check_index).severity = c_check_level_warning) OR
            (preupgradechecks(check_index).severity = c_check_level_recommend) ) LOOP
        IF NOT displayed_header THEN
            result := result || '  RECOMMENDED ACTIONS' || crlf ||
                                '  ===================' || crlf;
            displayed_header := true;
        END IF;
        result := result || preupgradecheck_t_to_text(preupgradechecks(check_index)) || crlf || crlf;
        check_index := check_index + 1;
    END LOOP;

    displayed_header := false;

    WHILE (check_index <= last_index) AND
          (preupgradechecks(check_index).fixup.fixAtStage = 'POST') AND
          (preupgradechecks(check_index).severity = c_check_level_info) LOOP
        IF NOT displayed_header THEN
            result := result || '  INFORMATION ONLY' || crlf ||
                                '  ================' || crlf;
            displayed_header := true;
        END IF;
        result := result || preupgradecheck_t_to_text(preupgradechecks(check_index)) || crlf || crlf;
        check_index := check_index + 1;
    END LOOP;

    IF check_index <= last_index THEN
        result := result || 'Internal Error - ' || to_char(last_index-check_index+1) ||
                  ' preupgrade checks were generated in XML but not emitted to TEXT.';
    END IF;

    RETURN result;
END preupgradechecks_t_to_text;


FUNCTION component_t_to_text(comp component_t) RETURN VARCHAR2
IS
    ui VARCHAR2(17);
BEGIN
    IF comp.install THEN
        ui := '[to be installed]';
    ELSE
        ui := '[to be upgraded]';
    END IF;

    RETURN rpad(comp.cname, 38) || ' ' || rpad(ui, 17) || ' ' || rpad(comp.status, 14);
END component_t_to_text;

FUNCTION components_t_to_text(components components_t) RETURN VARCHAR2
IS
    result VARCHAR2(4000);
    ui VARCHAR2(17);
    comp component_t;
    cols number_array_t := new number_array_t(2,38,1,17,1,14);  -- column spacing, including gaps between meaningful cols.
BEGIN
    result := column_format(cols,
                new string_array_t(' ','Oracle Component', ' ', 'Upgrade Action', ' ', 'Current Status') ) || crlf ||
              column_format(cols,
                new string_array_t(' ','----------------', ' ', '--------------', ' ', '--------------') ) || crlf;

    IF components.count = 0 THEN
        result := result ||
                  column_format(cols, new string_array_t(' ','None', ' ', ' ', ' ', ' ') ) || crlf;
    ELSE
        FOR components_index IN 1 .. components.count LOOP
            comp := components(components_index);
            IF comp.install THEN
                ui := '[to be installed]';
            ELSE
                ui := '[to be upgraded]';
            END IF;

            result := result ||
                      column_format(cols, new string_array_t(' ',comp.cname, ' ', ui, ' ', comp.status) ) || crlf;
        END LOOP;
    END IF;

    RETURN result;
END components_t_to_text;

FUNCTION tablespace_t_to_text(ts tablespace_t) RETURN VARCHAR2
IS
    suffix VARCHAR2(1000);
BEGIN


    -- IF ts.additional_size = 0 THEN
    -- The above comment made before frealvar edit which added IF ts_info(i).alloc = 0.
    -- why arent we looking at additional_size?
    IF ts.alloc = 0 THEN
        RETURN ts.name || ' tablespace does not have an associated temp file.' || crlf ||
               '     add one datafile of at least: ' || displayBytes(ROUND(ts.min)) || crlf; 
    ELSIF ts.inc_by = 0 THEN
        -- This behavior will have to be changed on releases post 12.2.0.1 as local UNDO
        -- tablespaces are now supported in this release.
        IF (ts.contents = 'UNDO' and NOT ts.fauto) THEN
            suffix := 'Warning: UNDO tablespace size is adequate for upgrading one database at a time.' || crlf ||
                      '         If you plan to upgrade multiple pluggable databases concurrently, then you must' || crlf ||
            	      '         ensure that the UNDO tablespace size is equal to at least the number of pluggable' || crlf ||
            	      '         databases that you upgrade concurrently, multiplied by ' || displayBytes(ts.min * c_mb) || crlf ||
            	      '         Failing to allocate sufficient space can result in the upgrade to fail.' || crlf;
        ELSE
            suffix := '';
        END IF;

        RETURN ts.name || ' tablespace is adequate for the upgrade.' || crlf ||
               ' minimum required size: ' || displayBytes(ts.min*c_mb) || crlf || suffix;
    ELSE
        RETURN ts.name || ' tablespace is not large enough for the upgrade.' || crlf ||
               '     currently allocated size: ' || displayBytes(ts.alloc*c_mb) || crlf ||
               '     resize the tablespace to at least: ' || displayBytes(ts.min*c_mb) || crlf ||
               '     tablespace ' || boolean_string(ts.fauto,'is','is NOT') || ' AUTOEXTEND ENABLED.' || crlf;
    END IF;
END tablespace_t_to_text;

FUNCTION tablespaces_t_to_text(tablespaces tablespaces_t) RETURN CLOB
IS
    result CLOB;
    this_tablespace tablespace_t;
    cols number_array_t := new number_array_t(5,30,1,-10,2,8,2,-10,2,6);  -- column spacing, including gaps between meaningful cols.
BEGIN
    result := '   + Adjust TABLESPACE SIZES as needed.' || crlf;
    result := result || column_format(cols,
                new string_array_t(' ',' ', ' ', ' ', ' ', 'Auto', ' ', C_ORACLE_HIGH_VERSION_4_DOTS, ' ', ' ') ) || crlf;
    result := result || column_format(cols,
                new string_array_t(' ','Tablespace', ' ', '   Size   ', ' ', 'Extend  ', ' ', 'Min Size  ', ' ', 'Action') ) || crlf;
    result := result || column_format(cols,
                new string_array_t(' ','----------', ' ', '----------', ' ', '--------', ' ', '----------', ' ', '------') ) || crlf || crlf;

    FOR tablespaces_index IN 1..tablespaces.count LOOP
        this_tablespace := tablespaces(tablespaces_index);

        result := result || column_format(cols, new string_array_t(' ', this_tablespace.name,
                                          ' ', displayBytes(this_tablespace.alloc*c_mb),
                                          ' ', boolean_string(this_tablespace.fauto, 'ENABLED','DISABLED'),
                                          ' ', displayBytes(this_tablespace.min*c_mb),
                                          ' ', boolean_string(this_tablespace.inc_by = 0,'None','Extend') ))
                  || crlf;
    END LOOP;

    result := result || crlf ||
              '     Note that ' || C_ORACLE_HIGH_VERSION_4_DOTS || ' minimum sizes are estimates.' || crlf ||
              '     If you plan to upgrade multiple pluggable databases concurrently,' || crlf ||
              '     then you must ensure that the UNDO tablespace size is equal to at least' || crlf ||
              '     the number of pluggable databases that you upgrade concurrently,' || crlf ||
              '     multiplied by that minimum.  Failing to allocate sufficient space can' || crlf ||
              '     cause the upgrade to fail.' || crlf;

    RETURN result;
END tablespaces_t_to_text;

FUNCTION archivelogs_t_to_text(archivelogs archivelogs_t) RETURN VARCHAR2
IS
BEGIN
    -- we do not emit text in manual mode for this element.
    RETURN '';
END archivelogs_t_to_text;

FUNCTION flashbacklogs_t_to_text(flashbacklogs flashbacklogs_t) RETURN VARCHAR2
IS 
BEGIN
    -- we do not emit text in manual mode for this element.
    RETURN '';
END flashbacklogs_t_to_text;

FUNCTION rollback_segments_t_to_text(rollback_segments rollback_segments_t) RETURN CLOB
IS
    result CLOB;
    this_rollback_segment rollback_segment_t;
    cols number_array_t := new number_array_t(5,39,2,7,2,10,2,-7);  -- column spacing, including gaps between meaningful cols.
BEGIN
    IF rollback_segments.count > 0 THEN
      result := result || '   + Use a large (minimum 70M) public rollback segment for the upgrade' || crlf ||
                          '     and take smaller public rollback segments OFFLINE.' || crlf || crlf;
      result := result || column_format(cols,
                new string_array_t(' ','Tablespace/Public Rollback Segment Name', ' ', 'Status', ' ', 'AutoExtend', ' ', 'Size') ) || crlf;
      result := result || column_format(cols,
                new string_array_t(' ','---------------------------------------', ' ', '------', ' ', '----------', ' ', '----') ) || crlf || crlf;

      FOR i IN 1..rollback_segments.count LOOP
          this_rollback_segment := rollback_segments(i);

          result := result || column_format(cols,
                    new string_array_t(' ',this_rollback_segment.tablespc || '/' || this_rollback_segment.name,
                                       ' ', this_rollback_segment.status,
                                       ' ', boolean_string(this_rollback_segment.auto > 0, 'ON', 'OFF'),
                                       ' ', displayBytes(this_rollback_segment.inuse*c_kb) )) || crlf;

          -- result := result || 'Rollback Segment ' || this_rollback_segment.name ||
          --                     ' in tablespace ' || this_rollback_segment.tablespc ||
          --                     ' is ' || this_rollback_segment.status || '; AUTOEXTEND is ' ||
          --                     boolean_string(this_rollback_segment.auto > 0, 'ON', 'OFF') || crlf ||
          --                     '     currently allocated: ' || displayBytes(this_rollback_segment.inuse*c_kb) || crlf||
          --                     '     next extent size: ' || displayBytes(this_rollback_segment.next*c_kb) ||
          --                             '; max extents: ' || to_char(this_rollback_segment.max_ext) || crlf;
      END LOOP;
    END IF;

    RETURN result;
END rollback_segments_t_to_text;


FUNCTION flashback_info_t_to_text(flashback_info flashback_info_t) RETURN VARCHAR2
IS
    result VARCHAR2(32767);
    enough_space BOOLEAN;
BEGIN
    IF flashback_info.name IS NOT NULL THEN
        enough_space := (flashback_info.dsize > flashback_info.used + flashback_info.min_fra_size);

        result := 'Ensure adequate disk space exists in the flash recovery area ' ||
                  'just before performing the upgrade.' || crlf ||
                   crlf ||
                  'At present, the enabled flash recovery area ' ||
                  boolean_string(enough_space,'IS ', 'IS NOT ') ||
                  ' large enough to handle the minimum estimated for the upgrade.' || crlf ||
                  crlf ||
                  'Flashback name:    ' || flashback_info.name || crlf ||
                  '    limit:         ' || displayBytes(flashback_info.limit) || crlf ||
                  '    used:          ' || displayBytes(flashback_info.used) || crlf ||
                  '    size:          ' || displayBytes(flashback_info.dsize) || crlf ||
                  '    reclaim:       ' || displayBytes(flashback_info.reclaimable) || crlf ||
                  '    files:         ' || to_char(flashback_info.files) || crlf || crlf;

        result := smart_pad(result,78,'     ');
        result := '   + ' || substr(result,6);
    END IF;

    RETURN result;
END flashback_info_t_to_text;


FUNCTION systemresource_t_to_text(systemresource systemresource_t) RETURN CLOB
IS 
BEGIN
    --
    --    systemresource XML tag is the first tag that potentially has actionable items
    --    so emit headings now.
    --    You could emit preupgrade_dir_path variable instead, but the filenamelen is
    --    apt to be long and distract from the output by crossing linelengths.
    --    
    RETURN '==============' || crlf ||
           'BEFORE UPGRADE' || crlf ||
           '==============' || crlf || crlf ||
           '  Run <preupgradeLogDirPath>/' || C_FIXUP_SCRIPT_NAME_PRE || ' to complete all ' || crlf ||
           '  of the BEFORE UPGRADE action items below marked with ''' || C_FIXUP_TAG || '''.' || crlf || crlf ||
           '  REQUIRED ACTIONS' || crlf ||
           '  ================' || crlf ||
           tablespaces_t_to_text(systemresource.tablespaces) || crlf ||
           rollback_segments_t_to_text(systemresource.rollback_segments) || crlf ||
           archivelogs_t_to_text(systemresource.archivelogs) ||
           flashbacklogs_t_to_text(systemresource.flashbacklogs);
           -- last two args above each return empty string.
END systemresource_t_to_text;

FUNCTION initparams_t_to_text(initparams initparams_t) RETURN CLOB
IS
    this_param_name  V$PARAMETER.NAME%TYPE;  -- has * if a mem param to display
    this_param parameter_xml_record_t;
    result CLOB;
    displayed_header boolean;
    cols number_array_t := new number_array_t(5,30,2,-20);  -- determines column widths for output table
BEGIN

    displayed_header := false;

    --
    --    Minimum values for numeric params
    --
    FOR i IN 1..initparams.update_params.count LOOP
        this_param := initparams.update_params(i);
        IF (this_param.type = c_param_type_number OR
                this_param.type = c_param_type_number_alt) THEN
            IF NOT displayed_header THEN
                result := result || 
                          '   + Update NUMERIC INITIALIZATION PARAMETERS to meet estimated minimums.' || crlf || crlf;


                result := result ||
                          column_format(cols,
                              new string_array_t(' ','Parameter',' ',C_ORACLE_HIGH_VERSION_4_DOTS || ' minimum') ) || crlf ||
                          column_format(cols,
                              new string_array_t(' ','---------',' ','------------------') ) || crlf;
                displayed_header := true;
            END IF;

            -- if this parameter is a memory parameter with a minimum
            -- recommended value to be displayed, then suffix name with '*'.
            -- note: memory parameters that are not going to be displayed
            --       would not have been copied to all_parameters from
            --       mem_parameters
            IF (db_is_cdb = FALSE OR db_is_root = TRUE) AND
               (sys.dbms_preup.is_size_this_memparam(this_param.name) = TRUE)
            THEN
              this_param_name := this_param.name || '*';
            ELSE
              this_param_name := this_param.name;
            END IF;

            result := result ||
                      column_format(cols,
                                    new string_array_t(' ', this_param_name, ' ', to_char(this_param.min_value)) )
                     || crlf; 
        END IF;
    END LOOP;

    -- add a note that the memory recommendations are for upgrade process
    IF is_show_mem_sizes = TRUE THEN
      result := result || crlf || '     * These minimum memory/pool sizes are recommended for the upgrade process' || crlf;
    END IF;

    -- put a blank line after the above table if we printed one.
    IF displayed_header THEN
        result := result || crlf || crlf;
    END IF;


    --
    --    String valued parameters whose value needs to be updated
    --
    displayed_header := false;

    FOR i IN 1..initparams.update_params.count LOOP
        this_param := initparams.update_params(i);
        IF NOT (this_param.type = c_param_type_number OR
                this_param.type = c_param_type_number_alt OR
                this_param.name = 'compatible' ) THEN
            IF NOT displayed_header THEN
                result := result ||
                          '   + Update NON-NUMERIC INITIALIZATION PARAMETERS.' || crlf ||
                          '     See Oracle documentation for details' || crlf || crlf ||
                          '     Parameter                      ' ||
                                'current value     ' ||
                                C_ORACLE_HIGH_VERSION_4_DOTS || ' new value ' || crlf ||
                          '     ------------------------------ ----------------  --------------------' || crlf;
                displayed_header := true;
            END IF;
            result := result || column_format(new number_array_t(5,30,1,16,2,20),
                       new string_array_t('     ',this_param.name, ' ', to_char(this_param.value), ' ',to_char(this_param.new_value)) )
                       || crlf; 
        END IF;
    END LOOP;

    -- put a blank line after the above table if we printed one.
    IF displayed_header THEN
        result := result || crlf || crlf;
    END IF;


    --
    --    Renamed parameters
    --
    displayed_header := false;

    FOR i IN 1..initparams.rename_params.count LOOP
        this_param := initparams.rename_params(i);
        IF this_param.new_value IS NULL THEN

            IF NOT displayed_header THEN
                result := result ||
                          '   + RENAME the following initialization parameters' || crlf ||
                          '     See Oracle documentation for details' || crlf || crlf ||
                          '     Parameter                      ' ||
                                C_ORACLE_HIGH_VERSION_4_DOTS || ' name ' || crlf ||
                          '     ------------------------------ ------------------------------' || crlf;
                displayed_header := true;
            END IF;
            result := result || column_format(new number_array_t(5,30,1,30),
                       new string_array_t('     ',this_param.name, ' ', to_char(this_param.renamed_to_name)) )
                       || crlf; 
        END IF;
    END LOOP;

    -- put a blank line after the above table if we printed one.
    IF displayed_header THEN
        result := result || crlf || crlf;
    END IF;



    --
    --    Paramaters whose both NAME and VALUE have changed
    --
    displayed_header := false;

    FOR i IN 1..initparams.rename_params.count LOOP
        this_param := initparams.rename_params(i);
        IF this_param.new_value IS NOT NULL THEN

            IF NOT displayed_header THEN
                result := result ||
                          '   + RENAME the following initialization parameters ' || crlf ||
                          '     AND SET NEW VALUES for them.  See Oracle documentation for details.' || crlf || crlf ||
                          '     Parameter                      Possible ' ||
                                C_ORACLE_HIGH_VERSION_4_DOTS || ' Name=Value ' || crlf ||
                          '     ------------------------------ ----------------------------------------' || crlf;
                displayed_header := true;
            END IF;
            result := result || column_format(new number_array_t(5,30,1,40),
                       new string_array_t('     ',this_param.name, ' ', this_param.renamed_to_name || '=' || this_param.new_value) )
                       || crlf; 
        END IF;
    END LOOP;

    -- put a blank line after the above table if we printed one.
    IF displayed_header THEN
        result := result || crlf || crlf;
    END IF;


    --
    --    OBSOLETE parameters
    --
    displayed_header := false;

    FOR i IN 1..initparams.remove_params.count LOOP
        this_param := initparams.remove_params(i);
        IF this_param.is_obsoleted THEN

            IF NOT displayed_header THEN
                result := result ||
                          '   + REMOVE the following OBSOLETE initialization parameters.' || crlf || crlf ||
                          '     Parameter                      ' || crlf ||
                          '     ------------------------------ ' || crlf;
                displayed_header := true;
            END IF;
            result := result || column_format(new number_array_t(5,30),
                                              new string_array_t('     ',this_param.name) )
                             || crlf;
        END IF;
    END LOOP;

    -- put a blank line after the above table if we printed one.
    IF displayed_header THEN
        result := result || crlf || crlf;
    END IF;


    RETURN result;

END initparams_t_to_text;

-- @@to_text

FUNCTION xml_to_text(xml CLOB) RETURN CLOB
IS
    result CLOB;
    element_name VARCHAR2(100);
    start_index NUMBER := 1;
    end_index NUMBER;  -- gets set to the index of the end of xml elements
    start_of_element_index NUMBER;  -- start of each element as it is found
    end_of_element_index NUMBER;  -- end of each element as it is found
    preupgradecheck preupgradecheck_t;
    preupgradechecks preupgradechecks_t;
    rdbmsup rdbmsup_t;
    my_database database_t;
    components components_t;
    systemresource systemresource_t;
    initparams initparams_t;
BEGIN
    end_index := length(xml);
    element_name := identify_next_element(xml, start_index, end_index,
                    start_of_element_index, end_of_element_index);
    WHILE (element_name IS NOT NULL) LOOP
        element_name := upper(element_name);
        IF debug THEN
            dbms_output.put_line('in xml_to_text, processing xml element: ' || element_name);
        END IF;

        CASE
            WHEN element_name = 'UPGRADE' THEN
                -- The UPGRADE element exists only on non-CDBs at the PLSQL level.  For CDBs the
                -- element is created in PreupgradeDriver.java, and is outside the visibility of this routine.
                -- so the result of UPGRADE element is just whatever content is inside the UPGRADE element.
                -- the +8 below is to skip over the current <Upgrade element.
                result := xml_to_text(substr(xml,start_of_element_index+8, end_of_element_index));
            WHEN element_name = 'RDBMSUP' THEN
                rdbmsup := parse_rdbmsup_xml(xml, start_of_element_index, end_of_element_index);
                    end_of_element_index := instr(xml, '>', start_of_element_index);
                result := result || rdbmsup_t_to_text(rdbmsup);
            WHEN element_name = 'DATABASE' THEN
                my_database := parse_database_xml(xml, start_of_element_index, end_of_element_index);
                result := result || database_t_to_text(my_database);
            WHEN element_name = 'PREUPGRADECHECKS' THEN
                preupgradechecks := parse_preupgradechecks_xml(xml, start_of_element_index, end_of_element_index);
                -- initparams was set in a previous iteration since they must precede preupgradechecks in XML.
                -- since the initparam information is not handled as a true CHECK.
                result := result || preupgradechecks_t_to_text(preupgradechecks,initparams);
            WHEN element_name = 'COMPONENTS' THEN
                components := parse_components_xml(xml, start_of_element_index, end_of_element_index);
                result := result || components_t_to_text(components);
            WHEN element_name = 'SYSTEMRESOURCE' THEN
                systemresource := parse_systemresource_xml(xml, start_of_element_index, end_of_element_index);
                result := result || systemresource_t_to_text(systemresource);
            WHEN element_name = 'INITPARAMS' THEN
                initparams := parse_initparams_xml(xml, start_of_element_index, end_of_element_index);
                result := result || initparams_t_to_text(initparams);
            ELSE
                internal_error('invalid internal XML.  Found unexpected element "' || element_name ||
                               '" while parsing outermost scope.' ||
                               ' Rerun preupgrade but generate XML output instead of' ||
                               ' text to identify problem for Oracle Support.');
        END CASE;

        --
        --    Format the output.
        -- 
        result := result || crlf || crlf;

        element_name := identify_next_element(xml, end_of_element_index+1, end_index,
                        start_of_element_index, end_of_element_index);
    END LOOP;

    RETURN result;
END xml_to_text;

FUNCTION get_failed_check_xml(check_name IN VARCHAR2,
                              substitution_parameter_values IN string_array_t,
                              detail_type IN VARCHAR2,
                              detail_info IN VARCHAR2)
                              RETURN VARCHAR2
IS
    my_check check_record_t;
    broken_rule VARCHAR2(4000);
    action VARCHAR2(4000);
    idx NUMBER;
    fixup_type VARCHAR2(4000);
    messageValues VARCHAR2(4000) := '';
    escapedOutput VARCHAR2(32767);
    detail_type_local VARCHAR2(20);
BEGIN
    FOR idx IN 1 .. substitution_parameter_values.count() LOOP
        --
        --    Escape any special characters to be emitted in the XML content, otherwise the XML processing may get sick.
        --    Make sure to perform substitutions the reverse order of how they are written.
        --
        escapedOutput := substitution_parameter_values(idx);
        escapedOutput := replace(escapedOutput, '&',  '&' || 'amp;');
        escapedOutput := replace(escapedOutput, '"',  '&' || 'quot;');
        escapedOutput := replace(escapedOutput, '''', '&' || 'apos;');
        escapedOutput := replace(escapedOutput, '<',  '&' || 'lt;');
        escapedOutput := replace(escapedOutput, '>',  '&' || 'gt;');

        messageValues := messageValues || '      <MessageValue Position="' || to_char(idx) || '">' ||
                                                 escapedOutput ||
                                                '</MessageValue>' || crlf;
    END LOOP;

    ---------------------------------
    my_check := get_check_record_by_name(check_name);

    --
    --    the text for the "broken_rule" and "action" needs to be calculated
    --    by making the substitutions for this failure context
    --
    broken_rule := my_check.broken_rule;
    action := my_check.action;
    FOR idx IN 1 .. substitution_parameter_values.count() LOOP
        broken_rule := REPLACE(broken_rule,
                               C_SUBSTITUTION_DELIMITER_OPEN || TO_CHAR(idx) || C_SUBSTITUTION_DELIMITER_CLOSE,
                               substitution_parameter_values(idx));
        action      := REPLACE(action,
                               C_SUBSTITUTION_DELIMITER_OPEN || TO_CHAR(idx) || C_SUBSTITUTION_DELIMITER_CLOSE,
                               substitution_parameter_values(idx));
    END LOOP;

    IF (my_check.auto_fixup_available) THEN
        fixup_type := 'AUTOMATIC';
    ELSE
        fixup_type := 'MANUAL';
    END IF;

    --
    --    As of 8/1/2015, all calls have detail_type = null.
    --    This is provided for backward compatibility for DBUA.
    --
    detail_type_local := detail_type;
    IF (detail_type_local IS NULL) THEN
        detail_type_local := 'TEXT';
    END IF;

    --
    --    OLD 12.1.0.2 FORMAT
    --
    -- return ('<PreUpgradeCheck ID="'      || my_check.name ||
    --                        '" Status="'  || my_check.severity  || '">' ||
    --                        crlf ||
    --             '<Message>' || crlf ||
    --                 '<Text>'   || my_check.rule  || '</Text>' || crlf || 
    --                 '<Cause>'  || broken_rule    || '</Cause>'  || crlf ||
    --                 '<Action>' || action         || '</Action>' || crlf ||
    --                 '<Detail Type="' || detail_type || '">' 
    --                     || detail_info || '</Detail>' || crlf ||
    --             '</Message>' || crlf ||
    --             '<FixUp Type="' || fixup_type  ||
    --                  '" FixAtStage="' || my_check.fixup_stage || '"/>' || crlf ||
    --         '</PreUpgradeCheck>' || crlf);    


    return '<PreUpgradeCheck ID="' || my_check.name || '" Status="'  || check_level_strings(my_check.severity)  || '">' || crlf ||
            '  <Rule>' || crlf ||
            '    <Message ID="CHECK.' || upper(my_check.name) || '.RULE">' || crlf ||
                   messageValues ||
            '    </Message>' || crlf ||
            '  </Rule>' || crlf ||
            '  <Broken_Rule>' || crlf ||
            '    <Message ID="CHECK.' || upper(my_check.name) || '.BROKEN_RULE">' || crlf ||
                   messageValues ||
            '    </Message>' || crlf ||
            '  </Broken_Rule>' || crlf ||
            '  <Action>' || crlf ||
            '    <Message ID="CHECK.' || upper(my_check.name) || '.ACTION">' || crlf ||
                   messageValues ||
            '    </Message>' || crlf ||
            '  </Action>' || crlf ||
            '  <Detail Type="' || detail_type_local || '">' || detail_info || '</Detail>' || crlf ||
            '  <FixUp Type="' || fixup_type  || '" FixAtStage="' || my_check.fixup_stage || '"/>' || crlf ||
            '</PreUpgradeCheck>' || crlf;
END get_failed_check_xml;


FUNCTION get_reserved_user_xml (username IN VARCHAR2,
                                first_version_reserved IN VARCHAR2)
                                RETURN VARCHAR2
IS
    user_exists  BOOLEAN;
    query_result SYS.USER$.USER#%TYPE;
BEGIN
    --
    --    first_version_reserved and/or last_version_reserved may be NULL to
    --    indicate that-that end of the version range is not bounded.
    --    Normally, first_version_reserved will be specified,
    --    and last_version_reserved will be null
    --

    --
    --    This CHECK identifies a problem only when the upgrade starts in
    --    a version which is BEFORE the Oracle reservation, and the upgrade
    --    destination/to/high version is EQUAL or AFTER the Oracle
    --    reservation version.
    --
    IF debug THEN
        dbms_output.put_line('in get_reserved_user_xml: version check starting: db_version=' ||
                             db_version_4_dots);
        dbms_output.put_line('in get_reserved_user_xml: version check starting: reserved  =' ||
                             first_version_reserved);
        dbms_output.put_line('in get_reserved_user_xml: version check starting: high vers =' ||
                             C_ORACLE_HIGH_VERSION_4_DOTS);
        dbms_output.put_line('in get_reserved_user_xml: compare(dbv,first)=' ||
                    to_char(dbms_registry_extended.compare_versions(db_version_4_dots, first_version_reserved)));
        dbms_output.put_line('in get_reserved_user_xml: compare(first,high)=' || 
                    to_char(dbms_registry_extended.compare_versions(first_version_reserved,C_ORACLE_HIGH_VERSION_4_DOTS)));
    END IF;

    IF (dbms_registry_extended.compare_versions(db_version_4_dots, first_version_reserved) = -1) AND
       (dbms_registry_extended.compare_versions(C_ORACLE_HIGH_VERSION_4_DOTS, first_version_reserved) >= 0) THEN
    
        IF debug THEN
            dbms_output.put_line('in get_reserved_user_xml, version checked, user must not exist in db');
        END IF;

        user_exists := TRUE;
        BEGIN
            EXECUTE IMMEDIATE
                'SELECT user# from SYS.USER$ WHERE name=:1'
                INTO query_result USING username;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                user_exists := FALSE;
        END;
    
        IF user_exists THEN
            RETURN get_failed_check_xml('oracle_reserved_users',
                new string_array_t(username,
                                   first_version_reserved,
                                   C_ORACLE_HIGH_VERSION_4_DOTS),
                null, null);
        END IF;
    END IF;

    RETURN '';

END get_reserved_user_xml;



--
--    End of XML, other misc routines
--
FUNCTION open_and_start_emitting_fixup(PRE_or_POST VARCHAR2) RETURN utl_file.file_type
IS
    fixup_script utl_file.file_type;
    genline VARCHAR2(4000);
    generation_timestamp VARCHAR2(20);
    cdb_suffix VARCHAR2(200);
    con_name_as_filename VARCHAR2(128);
BEGIN
    con_name_as_filename := replace(con_name,'$','_');
    BEGIN
        IF db_is_cdb THEN
            C_FIXUP_SCRIPT_NAME_PRE := C_FIXUP_SCRIPT_NAME_PRE_BASE || '_' || con_name_as_filename || '.sql';
            C_FIXUP_SCRIPT_NAME_POST := C_FIXUP_SCRIPT_NAME_POST_BASE || '_' || con_name_as_filename || '.sql';
        ELSE
            C_FIXUP_SCRIPT_NAME_PRE := C_FIXUP_SCRIPT_NAME_PRE_BASE || '.sql';
            C_FIXUP_SCRIPT_NAME_POST := C_FIXUP_SCRIPT_NAME_POST_BASE || '.sql';
        END IF;
        IF debug THEN
            dbms_output.put_line('C_FIXUP_SCRIPT_NAME_PRE = "' || C_FIXUP_SCRIPT_NAME_PRE || '"');
            dbms_output.put_line('C_FIXUP_SCRIPT_NAME_POST = "' || C_FIXUP_SCRIPT_NAME_POST || '"');
        END IF;

    	IF (PRE_or_POST = 'PRE') THEN
            fixup_script := utl_file.fopen('PREUPGRADE_DIR',REPLACE(C_FIXUP_SCRIPT_NAME_PRE,'$','_'), 'w');
        ELSIF (PRE_or_POST = 'POST') THEN
            fixup_script := utl_file.fopen('PREUPGRADE_DIR',REPLACE(C_FIXUP_SCRIPT_NAME_POST,'$','_'), 'w');

        ELSE
            internal_error('in open_and_start_emitting_fixup, PRE_or_POST=' || PRE_or_POST ||
                           ' but the only valid values are PRE and POST.');
        END IF;
    EXCEPTION
        WHEN OTHERS THEN
            dbms_output.put_line('ERROR - cannot open the ' || PRE_or_POST || ' fixup script for writing.' ||
                                 '  sqlerrm=' || sqlerrm || ' sqlcode=' || sqlcode);
            RETURN fixup_script;
    END;

    --
    --    Write header to the fixup Script
    --
    EXECUTE IMMEDIATE 'SELECT TO_CHAR(SYSTIMESTAMP,''YYYY-MM-DD HH24:MI:SS '') FROM SYS.DUAL'
                       INTO generation_timestamp;

    --
    --    a) If this is a cdb, the prefixup steps for multiple containers go into
    --    one prefixup file; and the postfixup steps for multiple containers go
    --    into one postfixup file.  In order to make this work, the fixup steps
    --    for a container will go into a IF stmt that gets executed if the
    --    container name for those fixup steps match the name of the current
    --    container connected to.
    --    b) For consistency between a non-cdb and cdb, we keep the same IF stmt
    --    format for the fixup steps for both non-cdbs and cdbs.  For
    --    non-cdbs, we match database names.  For cdbs, we match container names.
    --
    to_file(fixup_script, 'REM');
    to_file(fixup_script, 'REM    Oracle ' || PRE_or_POST || '-Upgrade Fixup Script');
    to_file(fixup_script, 'REM');
    to_file(fixup_script, 'REM    Auto-Generated by:       Oracle Preupgrade Script');
    to_file(fixup_script, 'REM                             Version: ' || C_ORACLE_HIGH_VERSION_4_DOTS ||
                                                           ' Build: ' || c_build);
    to_file(fixup_script, 'REM    Generated on:            ' || generation_timestamp);
    to_file(fixup_script, 'REM');
    to_file(fixup_script, 'REM    Source Database:         ' || db_name);
    to_file(fixup_script, 'REM    Source Database Version: ' || db_version_4_dots);
    to_file(fixup_script, 'REM    For Upgrade to Version:  ' || C_ORACLE_HIGH_VERSION_4_DOTS);
    to_file(fixup_script, 'REM');
    to_file(fixup_script, ' ');

    to_file(fixup_script, 'REM');
    to_file(fixup_script, 'REM    Setup Environment');
    to_file(fixup_script, 'REM');
    to_file(fixup_script, 'SET ECHO OFF SERVEROUTPUT ON FORMAT WRAPPED TAB OFF LINESIZE 200;' || crlf);

    to_file(fixup_script, ' ');

    --
    --    In a fixup script, there is a block with IF stmt for each database or
    --    container's fixup steps.
    --

    IF (PRE_or_POST = 'POST') THEN
      to_file(fixup_script, 'ALTER SESSION SET "_oracle_script" = TRUE;');
      to_file(fixup_script, 'VARIABLE admin_preupgrade_dir VARCHAR2(512);');
      IF db_is_cdb THEN
          to_file(fixup_script, 'VARIABLE current_container VARCHAR2(128);');
      END IF;
      to_file(fixup_script, ' ');
      to_file(fixup_script, 'REM');
      to_file(fixup_script, 'REM    point PREUPGRADE_DIR to OH/rdbms/admin');
      to_file(fixup_script, 'REM');
      to_file(fixup_script, 'DECLARE');
      to_file(fixup_script, '    oh VARCHAR2(4000);');
      to_file(fixup_script, 'BEGIN');
      to_file(fixup_script, '    dbms_system.get_env(''ORACLE_HOME'', oh);');
      to_file(fixup_script, '    :admin_preupgrade_dir := dbms_assert.enquote_literal(oh || ''/rdbms/admin'');');
      IF db_is_cdb THEN
          to_file(fixup_script, '    SELECT SYS_CONTEXT(''USERENV'', ''CON_NAME'') INTO :current_container FROM DUAL;');
      END IF;
      to_file(fixup_script, 'END;');
      to_file(fixup_script, '/');
      to_file(fixup_script, ' ');
      IF db_is_cdb THEN
          to_file(fixup_script, 'ALTER SESSION SET CONTAINER=CDB$ROOT;');
          to_file(fixup_script, ' ');
          to_file(fixup_script, 'DECLARE');
          to_file(fixup_script, '    command varchar2(4000);');
          to_file(fixup_script, 'BEGIN');
          to_file(fixup_script, '    command := ''CREATE OR REPLACE DIRECTORY PREUPGRADE_DIR SHARING=METADATA AS '' || :admin_preupgrade_dir;');
          to_file(fixup_script, '    EXECUTE IMMEDIATE command;');
          to_file(fixup_script, '    command := ''ALTER SESSION SET CONTAINER='' || :current_container;');
          to_file(fixup_script, '    EXECUTE IMMEDIATE command;');
          to_file(fixup_script, '    command := ''CREATE OR REPLACE DIRECTORY PREUPGRADE_DIR SHARING=METADATA AS '' || :admin_preupgrade_dir;');
          to_file(fixup_script, '    EXECUTE IMMEDIATE command;');
          to_file(fixup_script, 'END;');
          to_file(fixup_script, '/');
      ELSE
          to_file(fixup_script, 'DECLARE');
          to_file(fixup_script, '    command varchar2(4000);');
          to_file(fixup_script, 'BEGIN');
          to_file(fixup_script, '    command := ''CREATE OR REPLACE DIRECTORY PREUPGRADE_DIR AS '' || :admin_preupgrade_dir;');
          to_file(fixup_script, '    EXECUTE IMMEDIATE command;');
          to_file(fixup_script, 'END;');
          to_file(fixup_script, '/');
      END IF;
      to_file(fixup_script, ' ');
      to_file(fixup_script, '@?/rdbms/admin/dbms_registry_basic.sql');
      to_file(fixup_script, '@?/rdbms/admin/dbms_registry_extended.sql');
      to_file(fixup_script, ' ');
      to_file(fixup_script, ' ');
      to_file(fixup_script, 'REM');
      to_file(fixup_script, 'REM    Execute the preupgrade_package from the PREUPGRADE_DIR');
      to_file(fixup_script, 'REM    This is needed because the preupgrade_messages.properties file');
      to_file(fixup_script, 'REM    lives there too, and is read by preupgrade_package.sql using');
      to_file(fixup_script, 'REM    the PREUPGRADE_DIR.');
      to_file(fixup_script, 'REM');
      to_file(fixup_script, 'COLUMN directory_path NEW_VALUE admin_preupgrade_dir NOPRINT;');
      to_file(fixup_script, 'select directory_path from dba_directories where directory_name=''PREUPGRADE_DIR'';');
      to_file(fixup_script, 'set concat ''.'';');
      -- careful not to put the ampersand in front of admin_preupgrade_dir or it will force immediate substitution.
      to_file(fixup_script, '@&' || 'admin_preupgrade_dir./preupgrade_package.sql');
      to_file(fixup_script, 'COLUMN directory_path CLEAR;');
      to_file(fixup_script, '');
    END IF;

    to_file(fixup_script, 'DECLARE');
    to_file(fixup_script, '  db_name V$DATABASE.NAME%TYPE;');
    to_file(fixup_script, '  con_name VARCHAR2(128);');
    to_file(fixup_script, '  fixup_result BOOLEAN;');
    to_file(fixup_script, 'BEGIN ');
    to_file(fixup_script, '  --');
    to_file(fixup_script, '  --    Gather the current execution context');
    to_file(fixup_script, '  --');
    to_file(fixup_script, '  EXECUTE IMMEDIATE ');
    to_file(fixup_script, '    ''SELECT name FROM v$database'' INTO db_name;');
    to_file(fixup_script, '  EXECUTE IMMEDIATE ');
    to_file(fixup_script, '    ''SELECT dbms_preup.get_con_name FROM sys.dual'' INTO con_name;');
    to_file(fixup_script, '  ');
    to_file(fixup_script, '  ');

    --
    --    If the session currently connected to is of a database or container that
    --    matches the name in the IF stmt, then stay in the block and run the
    --    fixup steps.
    --    Else, if the names do not match, then continue on to the next block in
    --    the fixup script.
    --    this execute immediate not needed.  We do this once at package body init.
    --    EXECUTE IMMEDIATE
    --     'select dbms_preup.get_con_name from sys.dual' INTO con_name;
    --


    --
    --    Now validate the execution context is the same as when the script was generated
    --
    to_file(fixup_script, ' ');
    to_file(fixup_script, '  --');
    to_file(fixup_script, '  --    Now validate that the current execution context');
    to_file(fixup_script, '  --    matches the context when this script was generated.');
    to_file(fixup_script, '  --');

    to_file(fixup_script, '  IF db_name <> ''' || db_name || ''' THEN');
    to_file(fixup_script, '    dbms_output.put_line(''WARNING - This script was generated '' ||');
    to_file(fixup_script, '      ''for database ' || db_name || '.'');');
    to_file(fixup_script, '  END IF;        -- if db_name is ' || db_name);
    to_file(fixup_script, ' ');

    -- Duplicate code? these next few lines that identify the script being run are the same lines
    -- that generate the -- script header for this fixup script.  It might be a good idea
    -- to reuse that code rather than repeat it here.  Except for the word "Executing"
    to_file(fixup_script, '  dbms_output.put_line(''Executing Oracle ' || PRE_or_POST || '-Upgrade Fixup Script'');');
    to_file(fixup_script, '  dbms_output.put_line('' '');');
    to_file(fixup_script, '  dbms_output.put_line(''Auto-Generated by:       Oracle Preupgrade Script'');');
    to_file(fixup_script, '  dbms_output.put_line(''                         Version: ' || C_ORACLE_HIGH_VERSION_4_DOTS || ' Build: ' || c_build || ''');');
    to_file(fixup_script, '  dbms_output.put_line(''Generated on:            ' || generation_timestamp || ''');');
    to_file(fixup_script, '  dbms_output.put_line('' '');');
    to_file(fixup_script, '  dbms_output.put_line(''For Source Database:     ' || db_name || ''');');
    to_file(fixup_script, '  dbms_output.put_line(''Source Database Version: ' || db_version_4_dots || ''');');
    to_file(fixup_script, '  dbms_output.put_line(''For Upgrade to Version:  ' || C_ORACLE_HIGH_VERSION_4_DOTS || ''');');
    to_file(fixup_script, '  dbms_output.put_line('' '');');
                
    to_file(fixup_script, ' ');
    IF db_is_cdb THEN
        to_file(fixup_script, '  --');
        -- do not edit or remove the following line.  PreupgradeDriver.java depends on its content.
        to_file(fixup_script, '  -- Starting PDB ' || con_name);
        to_file(fixup_script, '  --');
        to_file(fixup_script, '  IF con_name = ''' || con_name || ''' THEN');
        to_file(fixup_script, '    dbms_output.put_line (''Executing in container:  ' || con_name || ''');');
        to_file(fixup_script, '    dbms_output.put_line('' '');');
    END IF;

    to_file(fixup_script, ' ');

    to_file(fixup_script, '    dbms_output.put_line(''                          Fixup'');');
    to_file(fixup_script, '    dbms_output.put_line(''Check Name                Status  Further DBA Action'');');
    to_file(fixup_script, '    dbms_output.put_line(''----------                ------  ------------------'');');

    RETURN fixup_script;
END open_and_start_emitting_fixup;

PROCEDURE finish_emitting_fixup(fixup_script IN OUT utl_file.file_type, PRE_or_POST VARCHAR2)
IS
BEGIN
    IF db_is_cdb THEN
        to_file(fixup_script, '  END IF;      -- if con_name is ' || con_name);
        --
        -- do not remove or edit this next line.  PreupgradeDriver.java depends on its content.
        --
        to_file(fixup_Script, '  -- Done PDB.');
    END IF;

    to_file(fixup_script, 'END;');
    to_file(fixup_script, '/');
    IF (PRE_or_POST = 'POST') THEN
        -- cannot do this for PRE script since it runs in low version and _oracle_script isn't supported in 11.2
        to_file(fixup_script, 'ALTER SESSION SET "_oracle_script" = FALSE;');
    END IF;
    to_file(fixup_script, ' ');

    BEGIN
        utl_file.fclose(fixup_script);
    EXCEPTION
        WHEN OTHERS THEN
            -- only way this happens is if to_file() above works, but cannot close file.
            -- proably a bad timing window.
            dbms_output.put_line('ERROR - could not close fixup script.  Stabilize file system and retry preupgrade.');
    END;
END finish_emitting_fixup;


FUNCTION run_fixup_only(check_name IN VARCHAR2, check_result_xml IN OUT VARCHAR2) RETURN BOOLEAN
IS
    call_fixup_statement VARCHAR2(4000);
    fixup_result NUMBER;
    tSqlcode NUMBER;
BEGIN
    IF debug THEN
        dbms_output.put_line('in run_fixup_only.  check_name=' || check_name);
    END IF;

    --
    --    Call the FIXUP
    --
    BEGIN
        call_fixup_statement := 'BEGIN ' ||
            ':1 := dbms_preup.' ||
                   dbms_assert.simple_sql_name(check_name) || '_fixup (:2, :3); ' ||
                  'END;';

        EXECUTE IMMEDIATE call_fixup_statement
            USING OUT fixup_result, IN OUT check_result_xml, IN OUT tSqlcode;
    EXCEPTION
        WHEN stringNotSimpleSQLName THEN
            --
            --    The checkname is invalid somehow.  Get out.
            --
            internal_error('Pre-Upgrade Package Requested Fixup ' ||
                           check_name || ' does not exist');
        WHEN e_undefinedFunction THEN
            internal_error('check "' || check_name || '" not implemented.');
        WHEN OTHERS THEN
            --
            --    This could happen if the CHECK itself threw an exception.
            --
            RAISE;
    END;

    IF debug THEN
        dbms_output.put_line('normal return from run_fixup_only.  Returning ' ||
            boolean_string(fixup_result = c_success));
    END IF;

    RETURN (fixup_result = c_success);
END run_fixup_only;

FUNCTION run_fixup(check_name VARCHAR2) RETURN BOOLEAN
IS
    this_check check_record_t;
    check_is_success BOOLEAN;
    fixup_is_success BOOLEAN;
    check_result_xml VARCHAR2(32767);
    original_message VARCHAR2(32767);
    dba_action       VARCHAR2(20);
    preupgradecheck preupgradecheck_t;
BEGIN
    IF debug THEN
        dbms_output.put_line('in run_fixup for check name: ' || check_name);
    END IF;

    --
    --    Before running the FIXUP, first run the CHECK again to
    --    see if the problem is still present.
    --
    check_is_success := run_check(check_name, check_result_xml);

    IF debug THEN
        dbms_output.put_line('in run_fixup for check name: ' || check_name || ' returned ' || boolean_string(check_is_success));
    END IF;

    IF (check_is_success) THEN
        dbms_output.put_line(rpad(check_name,26) || 'Passed  None');
        RETURN true;
    ELSE
        this_check := get_check_record_by_name(check_name);
        IF (NOT this_check.auto_fixup_available) THEN
            IF (this_check.severity = C_CHECK_LEVEL_ERROR) THEN
                dba_action := 'required.';
            ELSE
                dba_action := 'recommended.';
            END IF;
            dbms_output.put_line(rpad(check_name,26) || 'Failed  Manual fixup ' || dba_action);
            RETURN false;
        ELSE

            --
            --    run the fixup only
            --
            fixup_is_success := run_fixup_only(check_name, check_result_xml);

            IF (fixup_is_success) THEN
                --
                --    CHECK failed at start of this routine, the FIXUP ran
                --    and reported success.  Now, RERUN the CHECK to validate
                --    the problem has gone away.
                --
                check_is_success := run_check(check_name, check_result_xml);

                IF (check_is_success) THEN
                    dbms_output.put_line(rpad(check_name,26) || 'Passed  None');
                    RETURN true;
                ELSE
                    dbms_output.put_line(rpad(check_name,26) || 'Failed  ERROR: Manual fixup REQUIRED.  FIXUP and CHECK do not agree.');
                    dbms_output.put_line(' ');
                    dbms_output.put_line('The message it is currently reporting is:');
                    dbms_output.put_line(' ');
                    preupgradecheck := parse_preupgradecheck_xml(check_result_xml, 1, length(check_result_xml));
                    IF (preupgradecheck.id IS NULL) THEN
                        original_message := 'Unknown message';
                    ELSE
                        original_message := preupgradecheck_t_to_text(preupgradecheck);
                    END IF;
                    dbms_output.put_line(original_message);
                    dbms_output.put_line(' ');

                    RETURN false;
                END IF;
            ELSE
                dbms_output.put_line(rpad(check_name,26) || 'Failed  ERROR: Manual fixup REQUIRED.  FIXUP SCRIPT failed to resolve.');

                RETURN false;
            END IF;
        END IF;
    END IF;
END run_fixup;

PROCEDURE run_fixup_and_report (check_name VARCHAR2)
IS
    --
    --    This PROCEDURE is provided for backward compatibility and
    --    convenience.  It has no way of returning a success/failure status
    --    back to the caller.  The preferred way to run fixups is
    --    to call the FUNCTION run_fixup(check_name) which
    --    returns a boolean success status.
    --
    succeeded BOOLEAN;
BEGIN
    succeeded := run_fixup(check_name);
END run_fixup_and_report;


--------------------------- store_comp -----------------------------------
PROCEDURE store_comp (i       BINARY_INTEGER,
                      schema  VARCHAR2,
                      version VARCHAR2,
                      status  NUMBER)
IS
BEGIN
    cmp_info(i).processed := TRUE;
    cmp_info(i).status    := dbms_registry.status_name(status);
    cmp_info(i).version   := version;
    cmp_info(i).schema    := schema;
    EXECUTE IMMEDIATE
      'SELECT default_tablespace FROM sys.dba_users WHERE username =:1'
    INTO cmp_info(i).def_ts
    USING schema;
EXCEPTION
   WHEN NO_DATA_FOUND THEN NULL;
END store_comp;



PROCEDURE init_components
IS
  reg_cursor cursor_t;
  c_null     CHAR(1);
  c_cid      VARCHAR2(128);
  c_version  VARCHAR2(128);
  c_schema   VARCHAR2(128);
  n_schema   NUMBER;
  n_status   NUMBER;
  apex_will_be_upgraded BOOLEAN;
  db_full_apex_version VARCHAR2(40);
BEGIN
  -- Clear all variable component data
  FOR i IN 1..misc LOOP
    cmp_info(i).sys_kbytes:=     2*c_kb; 
    cmp_info(i).sysaux_kbytes:=  2*c_kb;
    cmp_info(i).def_ts_kbytes:=  0;
    cmp_info(i).ins_sys_kbytes:= 0;
    cmp_info(i).ins_def_kbytes:= 0;
    cmp_info(i).def_ts     := NULL;
    cmp_info(i).processed  := FALSE;
    cmp_info(i).install    := FALSE;
    cmp_info(i).archivelog_kbytes := 0;
    cmp_info(i).flashbacklog_kbytes := 0;
    cmp_info(i).pdb_archivelog_kb := 0;
  END LOOP;

  -- Load component id and name
  cmp_info(catalog).cid := 'CATALOG';
  cmp_info(catalog).cname := 'Oracle Catalog Views';
  cmp_info(catproc).cid := 'CATPROC';
  cmp_info(catproc).cname := 'Oracle Packages and Types';
  cmp_info(javavm).cid := 'JAVAVM';
  cmp_info(javavm).cname := 'JServer JAVA Virtual Machine';
  cmp_info(xml).cid := 'XML';
  cmp_info(xml).cname := 'Oracle XDK for Java';
  cmp_info(catjava).cid := 'CATJAVA';
  cmp_info(catjava).cname := 'Oracle Java Packages';
  cmp_info(xdb).cid := 'XDB';
  cmp_info(xdb).cname := 'Oracle XML Database';
  cmp_info(rac).cid := 'RAC';
  cmp_info(rac).cname := 'Real Application Clusters';
  cmp_info(owm).cid := 'OWM';
  cmp_info(owm).cname := 'Oracle Workspace Manager';
  cmp_info(odm).cid := 'ODM';
  cmp_info(odm).cname := 'Data Mining';
  cmp_info(mgw).cid := 'MGW';
  cmp_info(mgw).cname := 'Messaging Gateway';
  cmp_info(aps).cid := 'APS';
  cmp_info(aps).cname := 'OLAP Analytic Workspace';
  cmp_info(xoq).cid := 'XOQ';
  cmp_info(xoq).cname := 'Oracle OLAP API';
  cmp_info(ordim).cid := 'ORDIM';
  cmp_info(ordim).cname := 'Oracle Multimedia';
  cmp_info(sdo).cid := 'SDO';
  cmp_info(sdo).cname := 'Oracle Spatial';
  cmp_info(context).cid := 'CONTEXT';
  cmp_info(context).cname := 'Oracle Text';
  cmp_info(wk).cid := 'WK';
  cmp_info(wk).cname := 'Oracle Ultra Search';
  cmp_info(ols).cid := 'OLS';
  cmp_info(ols).cname := 'Oracle Label Security';
  cmp_info(exf).cid := 'EXF';
  cmp_info(exf).cname := 'Expression Filter';
  cmp_info(em).cid := 'EM';
  cmp_info(em).cname := 'Oracle Enterprise Manager Repository';
  cmp_info(rul).cid := 'RUL';
  cmp_info(rul).cname := 'Rule Manager';
  cmp_info(apex).cid := 'APEX';
  cmp_info(apex).cname := 'Oracle Application Express';
  cmp_info(dv).cid := 'DV';
  cmp_info(dv).cname := 'Oracle Database Vault'; 
  cmp_info(misc).cid := 'STATS';
  cmp_info(misc).cname := 'Gather Statistics';

  max_components_less_misc := misc - 1;
   
  -- Initialize comp script names

  IF (db_version_1_dot = '11.2') THEN
    -- 
    -- for 11.2, several components moved into
    -- catalog/catproc so they no longer have their own scripts
    --
    cmp_info(catalog).script := '?/rdbms/admin/catalog.sql';
    cmp_info(catproc).script := '?/rdbms/admin/catproc.sql';
    cmp_info(javavm).script  := '?/javavm/install/jvmpatch.sql'; 
    cmp_info(xml).script     := '?/xdk/admin/xmlpatch.sql';
    cmp_info(xdb).script     := '?/rdbms/admin/xdbpatch.sql';
    cmp_info(rac).script     := '?/rdbms/admin/catclust.sql';
    cmp_info(ols).script     := '?/rdbms/admin/olspatch.sql';
    cmp_info(exf).script     := '?/rdbms/admin/exfpatch.sql';
    cmp_info(rul).script     := '?/rdbms/admin/rulpatch.sql';
    cmp_info(owm).script     := '?/rdbms/admin/owmpatch.sql';
    cmp_info(ordim).script   := '?/ord/im/admin/impatch.sql';
    cmp_info(sdo).script     := '?/md/admin/sdopatch.sql';
    cmp_info(context).script := '?/ctx/admin/ctxpatch.sql';
    cmp_info(mgw).script     := '?/mgw/admin/mgwpatch.sql';
    cmp_info(aps).script     := '?/olap/admin/apspatch.sql';
    cmp_info(xoq).script     := '?/olap/admin/xoqpatch.sql';
    cmp_info(apex).script    := '?/apex/apxpatch.sql';
    cmp_info(dv).script      := '?/rdbms/admin/dvpatch.sql';
  ELSE
    cmp_info(catalog).script := '?/rdbms/admin/catalog.sql';
    cmp_info(catproc).script := '?/rdbms/admin/catproc.sql';
    cmp_info(javavm).script  := '?/javavm/install/jvmdbmig.sql'; 
    cmp_info(xml).script     := '?/xdk/admin/xmldbmig.sql';
    cmp_info(xdb).script     := '?/rdbms/admin/xdbdbmig.sql';
    cmp_info(rac).script     := '?/rdbms/admin/catclust.sql';
    cmp_info(ols).script     := '?/rdbms/admin/olsdbmig.sql';
    cmp_info(exf).script     := '?/rdbms/admin/exfdbmig.sql';
    cmp_info(rul).script     := '?/rdbms/admin/ruldbmig.sql';
    cmp_info(owm).script     := '?/rdbms/admin/owmdbmig.sql';
    cmp_info(odm).script     := '?/rdbms/admin/odmdbmig.sql';
    cmp_info(ordim).script   := '?/ord/im/admin/imdbmig.sql';
    cmp_info(sdo).script     := '?/md/admin/sdodbmig.sql';
    cmp_info(context).script := '?/ctx/admin/ctxdbmig.sql';
    cmp_info(wk).script      := '?/rdbms/admin/wkremov.sql';
    cmp_info(mgw).script     := '?/mgw/admin/mgwdbmig.sql';
    cmp_info(aps).script     := '?/olap/admin/apsdbmig.sql';
    cmp_info(xoq).script     := '?/olap/admin/xoqdbmig.sql';
    cmp_info(apex).script    := '?/apex/apxdbmig.sql';
    cmp_info(dv).script      := '?/rdbms/admin/dvdbmig.sql';
  END IF;

  -- *****************************************************************
  -- Store Release Dependent Data
  -- *****************************************************************

  -- kbytes for component installs (into SYSTEM and DEFAULT tablespaces)
  -- rae: add 10% for 11g .
  -- the '*1.2' below from point (a) to (b) are rae's .
  -- Point (a)
  cmp_info(javavm).ins_sys_kbytes:= 105972*1.2;  -- rae's
  cmp_info(xml).ins_sys_kbytes:=      4818*1.2;  -- rae's
  cmp_info(catjava).ins_sys_kbytes:=  5760*1.2;  -- rae's
  cmp_info(xdb).ins_sys_kbytes :=     10*c_kb * 1.2;
  IF db_block_size = 16384 THEN
    cmp_info(xdb).ins_def_kbytes:=   (88*2)*c_kb * 1.2;
  ELSE
    cmp_info(xdb).ins_def_kbytes:=   88*c_kb * 1.2;
  END IF;
  cmp_info(ordim).ins_sys_kbytes :=   10*c_kb * 1.2;  -- actually saw 1MB
  cmp_info(ordim).ins_def_kbytes :=   60*c_kb * 1.2;
  cmp_info(em).ins_sys_kbytes:= 0; -- was 22528*1.2 (rae's)
  cmp_info(em).ins_def_kbytes:= 0; -- was 51200*1.2 (rae's)
  -- Point (b)

  -- If there's XMLIndex on the XDB Repository during APEX upgrade
  -- from 11107 to 121 (apex v3 to v4), then 316M increase in xdb is seen.
  -- 316M = 85M (increase in lob segments + tables owned by xdb) +
  --        231M (increase in xmlindexes on xdb repository)
  -- (I.e., if no xmlindexes, then 85M of increase in XDB during APEX v3->v4
  -- upgrade.)

  IF (db_version_1_dot = '10.2') THEN
    -- mult by 1.1 for experimental noise
    cmp_info(catalog).sys_kbytes:=   67*c_kb * 1.1;
    cmp_info(catproc).sys_kbytes:=   (99+100)*c_kb * 1.1; -- catproc+catupend
    cmp_info(javavm).sys_kbytes:=   101*c_kb * 1.1;  
    cmp_info(xdb).sys_kbytes:=       12*c_kb * 1.1;  
    cmp_info(ordim).sys_kbytes:=     10*c_kb * 1.1;
    cmp_info(sdo).sys_kbytes:=       12*c_kb * 1.1;
    cmp_info(apex).sys_kbytes:=      81*c_kb * 1.1;

    cmp_info(catalog).sysaux_kbytes:=  14*c_kb * 1.1;
    cmp_info(catproc).sysaux_kbytes:=  31*c_kb * 1.1;  
    cmp_info(aps).sysaux_kbytes:=      36*c_kb * 1.1;

    cmp_info(context).def_ts_kbytes:=  2*c_kb; -- CTXSYS , default
    cmp_info(exf).def_ts_kbytes:=      2*c_kb; -- EXFSYS , default
    cmp_info(apex).def_ts_kbytes:=    320*c_kb * 1.1; -- FLOWS_
    cmp_info(ordim).def_ts_kbytes:=   15*c_kb * 1.1; -- ORDSYS
    cmp_info(sdo).def_ts_kbytes:=     38*c_kb * 1.1; -- MDSYS
    cmp_info(em).def_ts_kbytes:=                  0; -- SYSMAN
    cmp_info(catproc).def_ts_kbytes:= 31*c_kb * 1.1;
    cmp_info(owm).def_ts_kbytes:=      2*c_kb; -- WMSYS
    cmp_info(xdb).def_ts_kbytes:=     85*c_kb; -- XDB
    cmp_info(ols).def_ts_kbytes:=      2*c_kb; -- LBACSYS , default
    cmp_info(dv).def_ts_kbytes:=       2*c_kb; -- DVSYS , default
    cmp_info(aps).def_ts_kbytes :=    37*c_kb * 1.1;
    cmp_info(wk).def_ts_kbytes:=       0;      -- WK removed => 0 increase

  ELSIF (db_version_1_dot = '11.1') THEN 

    -- mult by 1.1 or 1.2 for experimental noise
    cmp_info(catalog).sys_kbytes:=  64*c_kb * 1.1;
    cmp_info(catproc).sys_kbytes:=  (59+123)*c_kb * 1.1; -- catproc+catupend 
    cmp_info(javavm).sys_kbytes:=   49*c_kb * 1.1;
    cmp_info(context).sys_kbytes:=   7*c_kb * 1.1;  
    cmp_info(xdb).sys_kbytes:=       2*c_kb * 1.1;  
    cmp_info(ordim).sys_kbytes:=    50*c_kb * 1.1;
    cmp_info(sdo).sys_kbytes:=      11*c_kb * 1.1;
    cmp_info(apex).sys_kbytes:=     50*c_kb * 1.1;
    cmp_info(em).sys_kbytes:=                   0;

    cmp_info(catalog).sysaux_kbytes:=   12*c_kb * 1.1;
    cmp_info(catproc).sysaux_kbytes:=   21*c_kb * 1.1;  
    cmp_info(aps).sysaux_kbytes:=       13*c_kb * 1.1;

    cmp_info(context).def_ts_kbytes:=  2*c_kb; -- CTXSYS , default
    cmp_info(exf).def_ts_kbytes:=      2*c_kb; -- EXFSYS , default
    cmp_info(apex).def_ts_kbytes :=  320*c_kb * 1.1; -- FLOWS_
    cmp_info(sdo).def_ts_kbytes:=     23*c_kb * 1.1; -- MDSYS
    cmp_info(ordim).def_ts_kbytes:=   15*c_kb * 1.1; -- ORDSYS
    cmp_info(em).def_ts_kbytes:=      0;       -- SYSMAN, removed, 0 increase
    cmp_info(catproc).def_ts_kbytes:= 21*c_kb * 1.1;
    cmp_info(owm).def_ts_kbytes:=      2*c_kb;       -- WMSYS, default
    cmp_info(xdb).def_ts_kbytes:=     85*c_kb; -- XDB
    cmp_info(ols).def_ts_kbytes:=      2*c_kb;       -- LBACSYS , default
    cmp_info(dv).def_ts_kbytes:=       2*c_kb;       -- DVSYS , default
    cmp_info(wk).def_ts_kbytes:=       0;        -- WK removed => 0 increase

  ELSIF (db_version_1_dot = '11.2') THEN

    -- mult by 1.1 or 1.2 for experimental noise
    cmp_info(catalog).sys_kbytes:=  58*c_kb * 1.1;
    cmp_info(catproc).sys_kbytes:=  (31+123)*c_kb * 1.1;  -- catproc+catupend
    cmp_info(javavm).sys_kbytes:=   10*c_kb * 1.1;
    cmp_info(context).sys_kbytes:=   4*c_kb * 1.1;  
    cmp_info(xdb).sys_kbytes:=       2*c_kb * 1.1;  
    cmp_info(sdo).sys_kbytes:=       2*c_kb * 1.1;
    cmp_info(apex).sys_kbytes:=     50*c_kb * 1.1;

    cmp_info(catalog).sysaux_kbytes:=   2*c_kb;  -- default
    cmp_info(catproc).sysaux_kbytes:=  27*c_kb * 1.1;

    -- apex: 269 is the amount of space needed (as seen from experiments) +
    --       50 is the padding because if apex is in its own tablespace
    --       then having a padding would be good
    cmp_info(apex).def_ts_kbytes :=  320*c_kb * 1.1; -- FLOWS_

    cmp_info(sdo).def_ts_kbytes:=     10*c_kb * 1.1; -- MDSYS
    cmp_info(ordim).def_ts_kbytes:=    2*c_kb;       -- ORDSYS , default
    cmp_info(em).def_ts_kbytes:=       0;      -- SYSMAN , 0 increase
    cmp_info(owm).def_ts_kbytes:=      2*c_kb; -- WMSYS , default
    cmp_info(xdb).def_ts_kbytes:=     85*c_kb; -- XDB , default
    cmp_info(aps).def_ts_kbytes :=     2*c_kb; -- default
    cmp_info(ols).def_ts_kbytes:=      2*c_kb; -- LBACSYS , default
    cmp_info(dv).def_ts_kbytes:=       2*c_kb; -- DVSYS , default
    cmp_info(wk).def_ts_kbytes:=       0;      -- WK removed => 0 increase

  ELSIF (db_version_1_dot = '12.1') THEN 
    -- initial estimates of growth in patch release
    -- let's use 112 values for now (copy and paste of 112 values from above)
    -- CML: need to update for 121 patch upgrades

    -- mult by 1.1 or 1.2 for experimental noise
    cmp_info(catalog).sys_kbytes:=  58*c_kb * 1.1;
    cmp_info(catproc).sys_kbytes:=  (31+123)*c_kb * 1.1;  -- catproc+catupend
    cmp_info(javavm).sys_kbytes:=   10*c_kb * 1.1;
    cmp_info(context).sys_kbytes:=   4*c_kb * 1.1;  
    cmp_info(xdb).sys_kbytes:=       2*c_kb * 1.1;  
    cmp_info(sdo).sys_kbytes:=       2*c_kb * 1.1;
    cmp_info(apex).sys_kbytes:=     50*c_kb * 1.1;

    cmp_info(catalog).sysaux_kbytes:=   2*c_kb;  -- default
    cmp_info(catproc).sysaux_kbytes:=  27*c_kb * 1.2;

    cmp_info(apex).def_ts_kbytes :=  320*c_kb * 1.1; -- FLOWS_
    cmp_info(sdo).def_ts_kbytes:=     10*c_kb * 1.1; -- MDSYS
    cmp_info(ordim).def_ts_kbytes:=    2*c_kb;       -- ORDSYS , default
    cmp_info(em).def_ts_kbytes:=       0;      -- SYSMAN , 0 increase
    cmp_info(owm).def_ts_kbytes:=      2*c_kb; -- WMSYS , default
    cmp_info(xdb).def_ts_kbytes:=     85*c_kb; -- XDB , default
    cmp_info(aps).def_ts_kbytes :=     2*c_kb; -- default
    cmp_info(ols).def_ts_kbytes:=      2*c_kb; -- LBACSYS , default
    cmp_info(dv).def_ts_kbytes:=       2*c_kb; -- DVSYS , default
    cmp_info(wk).def_ts_kbytes:=       0;      -- WK removed => 0 increase
  ELSE
      --
      --    Unsupported/Unknown Version
      --    in this case, we need to assign some sort of default/reasonable
      --    values to the cmp_info() and continue and presume that
      --    supported_version_check() will identify and report the
      --    issue back to the user.
      --
      -- dbms_output.put_line('Unknown/Unsupported Version: ' || db_version_4_dots);
      NULL;
  END IF;

  -- Flashback and archivelog for each database component

  -- note: The unit of measurement in archivelog_kbytes and flashbacklog_kbytes
  --       below are in Kb.
  --       For example:
  -- cmp_info(catalog).archivelog_kbytes   := 580*c_kb;  <= is 593920 Kb
  -- cmp_info(catalog).flashbacklog_kbytes := 285*c_kb;  <= is 291840 Kb

  -- cml: Although AMD is not in 12c, let's save these 2 entries in case
  --      the amd info below is needed for future backports to older releases.
  --  cmp_info(amd).archivelog_kbytes       := 43*c_kb;
  --  cmp_info(amd).flashbacklog_kbytes     := 55*c_kb;


  cmp_info(catalog).archivelog_kbytes   := 580*c_kb;
  cmp_info(catalog).flashbacklog_kbytes := 285*c_kb;

  -- catproc = catproc + utlmmig-and-catuppst + fudge-that-can-be-used-for-utlrp
  cmp_info(catproc).archivelog_kbytes   := (588+410+312)*c_kb;
  cmp_info(catproc).flashbacklog_kbytes := (719+0+210)*c_kb;

  -- catalog-and-catproc + utlmmig-and-catuppst + fudge
  cmp_info(catproc).pdb_archivelog_kb := (928+225+156)*c_kb;

  cmp_info(javavm).archivelog_kbytes    := 731*c_kb;
  cmp_info(javavm).flashbacklog_kbytes  := 752*c_kb;
  cmp_info(javavm).pdb_archivelog_kb    := 334*c_kb;

  cmp_info(xml).archivelog_kbytes       := 128*c_kb;
  cmp_info(xml).pdb_archivelog_kb       :=  32*c_kb;

  cmp_info(aps).archivelog_kbytes       :=  77*c_kb;
  cmp_info(aps).flashbacklog_kbytes     := 241*c_kb;
  cmp_info(aps).pdb_archivelog_kb       :=  72*c_kb;

  cmp_info(ols).archivelog_kbytes       := 36*c_kb;

  cmp_info(dv).archivelog_kbytes        := 47*c_kb;
  cmp_info(dv).pdb_archivelog_kb        := 34*c_kb;

  cmp_info(context).archivelog_kbytes   := 98*c_kb;
  cmp_info(context).pdb_archivelog_kb   := 38*c_kb;

  cmp_info(xdb).archivelog_kbytes       := 128*c_kb;
  cmp_info(xdb).pdb_archivelog_kb       :=  68*c_kb;

  cmp_info(catjava).archivelog_kbytes   := 41*c_kb;

  cmp_info(owm).archivelog_kbytes       := 61*c_kb;
  cmp_info(owm).pdb_archivelog_kb       := 32*c_kb;

  cmp_info(ordim).archivelog_kbytes     := 302*c_kb;
  cmp_info(ordim).pdb_archivelog_kb     := 150*c_kb;

  cmp_info(sdo).archivelog_kbytes       := 799*c_kb;
  cmp_info(sdo).flashbacklog_kbytes     := 251*c_kb;
  cmp_info(sdo).pdb_archivelog_kb       := 328*c_kb;

  cmp_info(apex).archivelog_kbytes      := 1060*c_kb;
  cmp_info(apex).pdb_archivelog_kb      :=  968*c_kb;

  -- For tablespace sizing
  -- CML: TS: estimate for utlrp later?  utlrp space goes into system and
  --          system right now is not sized for utlrp.
  cmp_info(misc).sys_kbytes:=     100*c_kb;  -- misc: round up to 100M fudge
  cmp_info(misc).sysaux_kbytes:=   50*c_kb;  -- misc: round up to  50M fudge

  BEGIN
    EXECUTE IMMEDIATE
      'SELECT version FROM sys.registry$ WHERE cid = ''APEX'' and namespace=''SERVER'''
      INTO db_full_apex_version;
    apex_will_be_upgraded := (dbms_registry_extended.compare_versions(db_full_apex_version, high_version_apex, 1) < 0);
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      apex_will_be_upgraded := FALSE;
  END;

  -- store the value into a global variable, which will be used elsewhere
  is_apex_will_be_upgraded := apex_will_be_upgraded;
  IF debug_archive_fra = TRUE THEN
    IF is_apex_will_be_upgraded = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: is_apex_will_be_upgraded TRUE');
    ELSE
      dbms_output.put_line('ARCHIVE/FRA: is_apex_will_be_upgraded FALSE');
    END IF;
  END IF;

  --
  -- Grab the Component ID (varchar2) from
  -- registry, and then see if the 
  -- schema exists in USER$ below which means its
  -- in use in this database.
  --
  OPEN reg_cursor FOR 
     'SELECT cid, status, version, schema# 
      FROM sys.registry$ WHERE namespace =''SERVER''';

  LOOP

    FETCH reg_cursor INTO c_cid, n_status, c_version, n_schema;
    EXIT WHEN reg_cursor%NOTFOUND;

    -- If the status is not  REMOVED or REMOVING
    IF n_status NOT IN (99,8) 
    THEN
      EXECUTE IMMEDIATE 'SELECT name FROM sys.user$  WHERE user#=:1'
      INTO c_schema
      USING n_schema;

      FOR i IN 1..max_components_less_misc LOOP
        IF c_cid = cmp_info(i).cid 
        THEN
          -- unusual rules for APEX.  If it isn't slated for upgrade, do not process.
          -- IF not ((c_cid = apex) and (not apex_will_be_upgraded)) THEN
          -- Continue processing as done historically.
            store_comp(i, c_schema, c_version, n_status);
          -- END;
          EXIT; -- from component search loop
        END IF;
      END LOOP;  -- ignore if not in component list
    END IF;
  END LOOP;
  CLOSE reg_cursor;


  -- Ultra Search not in 10.1.0.2 registry so check schema
  IF NOT cmp_info(wk).processed THEN
    BEGIN
      EXECUTE IMMEDIATE 'SELECT NULL FROM sys.user$ WHERE name = ''WKSYS'''
    INTO c_null;
      store_comp(wk, 'WKSYS', db_version_4_dots, NULL);
    EXCEPTION
         WHEN NO_DATA_FOUND THEN NULL;
    END;
  END IF;

  -- Check for HTML DB in 9.2.0 and 10.1 databases
  -- 121:  Is this needed
  IF NOT cmp_info(apex).processed THEN
    BEGIN
      EXECUTE IMMEDIATE 'SELECT FLOWS_010500.wwv_flows_release from sys.dual'
      INTO c_version;
      store_comp(apex,'FLOWS_010500',c_version, NULL);
    EXCEPTION
         WHEN OTHERS THEN NULL;
    END;

  -- 121:  Is this needed
    BEGIN
      EXECUTE IMMEDIATE 'SELECT FLOWS_010600.wwv_flows_release from sys.dual'
      INTO c_version;
      store_comp(apex,'FLOWS_010600',c_version, NULL);
    EXCEPTION
       WHEN OTHERS THEN NULL;
    END;

  -- Check for APEX in 10.2 databases
    BEGIN
      EXECUTE IMMEDIATE 'SELECT FLOWS_020000.wwv_flows_release from sys.dual'
      INTO c_version;
      store_comp(apex,'FLOWS_020000',c_version, NULL);
    EXCEPTION
       WHEN OTHERS THEN NULL;
    END;

    BEGIN
      EXECUTE IMMEDIATE 'SELECT FLOWS_020100.wwv_flows_release from sys.dual'
      INTO c_version;
      store_comp(apex,'FLOWS_020100',c_version, NULL);
    EXCEPTION
       WHEN OTHERS THEN NULL;
    END;
  END IF;

  -- Database Vault not in registry so check for dvsys schema
  IF NOT cmp_info(dv).processed THEN
    BEGIN
      EXECUTE IMMEDIATE 'SELECT NULL FROM sys.user$ WHERE name = ''DVSYS'''
      INTO  c_null;
      store_comp(dv, 'DVSYS', '10.2.0', NULL);
    EXCEPTION
       WHEN NO_DATA_FOUND THEN NULL;
    END;
  END IF;

  -- CML: TS: estimate for utlrp later?
    -- Consider MISC (miscellaneous) in registry because
    -- cmp_info(misc).processed has to be equal to TRUE before the tablespace
    -- sizing algorithm will consider the space needed for MISC.
    -- this call will set 'cmp_info(misc).processed := TRUE;'
  store_comp(misc, 'SYS', NULL, NULL);      


  IF (db_version_1_dot != '11.2') THEN -- install required components on major release only
    -- if SDO, ORDIM, WK, EXF, or ODM components are present, need JAVAVM
    IF NOT cmp_info(javavm).processed THEN
      IF cmp_info(ordim).processed OR cmp_info(wk).processed OR 
           cmp_info(exf).processed OR cmp_info(sdo).processed 
      THEN
        store_comp(javavm, 'SYS', NULL, NULL);           
        cmp_info(javavm).install := TRUE;
        store_comp(catjava, 'SYS', NULL, NULL);           
        cmp_info(catjava).install := TRUE;
      END IF;
    END IF;
 
    -- If there is a JAVAVM component
    -- THEN include the CATJAVA component.
    IF cmp_info(javavm).processed AND NOT cmp_info(catjava).processed 
    THEN
      store_comp(catjava, 'SYS', NULL, NULL);           
      cmp_info(catjava).install := TRUE;
    END IF;

    -- If interMedia or Spatial component, but no XML, Then
    -- install XML
    IF NOT cmp_info(xml).processed AND
         (cmp_info(ordim).processed OR cmp_info(sdo).processed) 
    THEN
      store_comp(xml, 'SYS', NULL, NULL);           
      cmp_info(xml).install := TRUE;
    END IF;
   
    -- If no XDB, Then install XDB
    IF NOT cmp_info(xdb).processed THEN
      store_comp(xdb, 'XDB', NULL, NULL);           
      cmp_info(xdb).install := TRUE;
      cmp_info(xdb).def_ts := 'SYSAUX';
    END IF;
   
    -- If Spatial component, but no ORDIM, Then
    -- install ORDIM
    IF NOT cmp_info(ordim).processed AND
         (cmp_info(sdo).processed)
    THEN
      store_comp(ordim, 'ORDSYS', NULL, NULL);           
      cmp_info(ordim).install := TRUE;
      cmp_info(ordim).def_ts := 'SYSAUX';
    END IF;
 END IF;  -- not for patch release

END init_components;


--
-- creates a record in mem_parameters table
-- this table will contain computational info for MEMORY sizing
-- 
PROCEDURE store_memparam_record (name     VARCHAR2,
                                 minval   NUMBER,
                                 memvp    IN OUT MEMPARAMETER_TABLE_T)
IS
BEGIN
  -- if we are not sizing for this memory parameter, then don't create
  -- a record for it
  IF is_size_this_memparam(name) = TRUE THEN
    memvp(name).name := name;
    memvp(name).old_value := all_parameters(name).value;
    memvp(name).min_value := minval;
    memvp(name).dif_value := 0;
    memvp(name).isdefault := all_parameters(name).isdefault;
    memvp(name).display := FALSE;
  END IF;
END store_memparam_record;

PROCEDURE store_minval_param(paramname VARCHAR2, min_value INTEGER)
IS
BEGIN
  -- The purpose of recording minimum value settings for certain parameters is to
  -- ensure that the user's existing settings conform to new minimum standards in the
  -- higher release.  If the user has no setting for a parameter, there's no need to
  -- worry about whether a minimum has been violated.
  IF all_parameters.exists(paramname) THEN
    -- if the parameter does not exist its because it does not exist in this RELEASE.  No need to record it has been renamed
    all_parameters(paramname).min_value := min_value;
  END IF;
END store_minval_param;


PROCEDURE store_renamed_param (oldname VARCHAR2, newname VARCHAR2)
IS
BEGIN
  IF all_parameters.exists(oldname) THEN
    -- if the parameter does not exist its because it does not exist in this RELEASE.  No need to record it has been renamed
    all_parameters(oldname).renamed_to_name := newname;
  END IF;
END store_renamed_param;

--
-- The below queries should be executed in the main rdbms version
-- otherwise the list might not be up to date
--
-- List of deprecated parameters
-- select name from v$parameter where isdeprecated = 'TRUE' order by name;
-- List of obsolete parameters
-- select name from v$obsolete_parameter order by name;
--
-- Note: The queries will return all the deprectaed/obsolete parameters
-- not only the ones that apply for the current version where the query
-- is executed
--
PROCEDURE store_removed_param (name VARCHAR2, version VARCHAR2, deprecated BOOLEAN)
IS
BEGIN
  -- no need to record a removed parameter if it does not exist for this release.
  IF all_parameters.exists(name) THEN
    IF deprecated THEN
        all_parameters(name).is_deprecated := true;
    ELSE
        all_parameters(name).is_obsoleted  := true;
    END IF;
  END IF;
END store_removed_param;

PROCEDURE store_renamed_param_and_value (oldname  VARCHAR2, oldvalue VARCHAR2,
                                         newname  VARCHAR2, newvalue VARCHAR2)
IS
BEGIN
  -- if the parameter does not exist for the source db release version, no need to record it.
  IF all_parameters.exists(oldname) AND
     all_parameters(oldname).value = oldvalue THEN
    all_parameters(oldname).renamed_to_name := newname;
    all_parameters(oldname).new_value := newvalue;
  END IF;
END store_renamed_param_and_value;

PROCEDURE init_parameters
IS
  p_name  SYS.V$PARAMETER.NAME%TYPE;
  p_type  SYS.V$PARAMETER.TYPE%TYPE;
  p_value SYS.V$PARAMETER.VALUE%TYPE;
  p_isdefault SYS.V$PARAMETER.ISDEFAULT%TYPE;
  p_isspecified SYS.V$SPPARAMETER.ISSPECIFIED%TYPE; 
  parameter_record parameter_record_t;
  param_cursor cursor_t;
  t_null CHAR(1);
BEGIN
 -- Adding an outer join to v$spparameter to 1) read isspecified column to know if a given parameter is in the spfile and 2) consider v$parameter as the complete list of parameters (some may not be present in the v$sppfile). 
  OPEN param_cursor FOR 'select distinct vp.name, vp.type, vp.value,vp.isdefault, nvl(vsp.isspecified,''NOSPF'') is_spspecified
                         from sys.v$parameter vp left outer join sys.v$spparameter vsp on vp.name=vsp.name
                         and (vsp.sid=''*'' or vsp.sid in (select instance_name from v$instance) ) order by name';
  LOOP
    FETCH param_cursor INTO p_name, p_type, p_value, p_isdefault,p_isspecified;
    EXIT WHEN param_cursor%NOTFOUND;

    -- parameter_record := new parameter_record_t;
    -- parameter_record.name := p_name;
    -- parameter_record.type := p_type;
    -- parameter_record.value := p_value;
    -- all_parameters(p_name) := parameter_record;
    all_parameters(p_name).name := p_name;
    all_parameters(p_name).type := p_type;
    all_parameters(p_name).value := p_value;
    all_parameters(p_name).isdefault := p_isdefault;
    all_parameters(p_name).isspecified := p_isspecified;

    IF debug THEN
        dbms_output.put_line('source database has parameter: ' || p_name || '(' || p_type || ')=' || p_value);
    END IF;

  END LOOP;

  store_removed_param('checkpoint_process', '8.0', FALSE);
  store_removed_param('fast_cache_flush', '8.0', FALSE);
  store_removed_param('gc_db_locks', '8.0', FALSE);
  store_removed_param('gc_freelist_groups', '8.0', FALSE);
  store_removed_param('gc_rollback_segments', '8.0', FALSE);
  store_removed_param('gc_save_rollback_locks', '8.0', FALSE);
  store_removed_param('gc_segments', '8.0', FALSE);
  store_removed_param('gc_tablespaces', '8.0', FALSE);
  store_removed_param('io_timeout', '8.0', FALSE);
  store_removed_param('init_sql_files', '8.0', FALSE);
  store_removed_param('ipq_address', '8.0', FALSE);
  store_removed_param('ipq_net', '8.0', FALSE);
  store_removed_param('lm_domains', '8.0', FALSE);
  store_removed_param('lm_non_fault_tolerant', '8.0', FALSE);
  store_removed_param('mls_label_format', '8.0', FALSE);
  store_removed_param('optimizer_parallel_pass', '8.0', FALSE);
  store_removed_param('parallel_default_max_scans', '8.0', FALSE);
  store_removed_param('parallel_default_scan_size', '8.0', FALSE);
  store_removed_param('post_wait_device', '8.0', FALSE);
  store_removed_param('sequence_cache_hash_buckets', '8.0', FALSE);
  store_removed_param('unlimited_rollback_segments', '8.0', FALSE);
  store_removed_param('use_readv', '8.0', FALSE);
  store_removed_param('use_sigio', '8.0', FALSE);
  store_removed_param('v733_plans_enabled', '8.0', FALSE);


  -- Obsolete in 8.1
  store_removed_param('allow_partial_sn_results', '8.1', FALSE);
  store_removed_param('arch_io_slaves', '8.1', FALSE);
  store_removed_param('b_tree_bitmap_plans', '8.1', FALSE);
  store_removed_param('backup_disk_io_slaves', '8.1', FALSE);
  store_removed_param('cache_size_threshold', '8.1', FALSE);
  store_removed_param('cleanup_rollback_entries', '8.1', FALSE);
  store_removed_param('close_cached_open_cursors', '8.1', FALSE);
  store_removed_param('complex_view_merging', '8.1', FALSE);
  store_removed_param('db_block_checkpoint_batch', '8.1', FALSE);
  store_removed_param('db_block_lru_extended_statistics', '8.1', FALSE);
  store_removed_param('db_block_lru_statistics', '8.1', FALSE);
  store_removed_param('db_file_simultaneous_writes', '8.1', FALSE);
  store_removed_param('delayed_logging_block_cleanouts', '8.1', FALSE);
  store_removed_param('discrete_transactions_enabled', '8.1', FALSE);
  store_removed_param('distributed_recovery_connection_hold_time', '8.1', FALSE);
  store_removed_param('ent_domain_name', '8.1', FALSE);
  store_removed_param('fast_full_scan_enabled', '8.1', FALSE);
  store_removed_param('freeze_DB_for_fast_instance_recovery', '8.1', FALSE);
  store_removed_param('gc_latches', '8.1', FALSE);
  store_removed_param('gc_lck_procs', '8.1', FALSE);
  store_removed_param('job_queue_keep_connections', '8.1', FALSE);
  store_removed_param('large_pool_min_alloc', '8.1', FALSE);
  store_removed_param('lgwr_io_slaves', '8.1', FALSE);
  store_removed_param('lm_locks', '8.1', FALSE);
  store_removed_param('lm_procs', '8.1', FALSE);
  store_removed_param('lm_ress', '8.1', FALSE);
  store_removed_param('lock_sga_areas', '8.1', FALSE);
  store_removed_param('log_archive_buffer_size', '8.1', FALSE);
  store_removed_param('log_archive_buffers', '8.1', FALSE);
  store_removed_param('log_block_checksum', '8.1', FALSE);
  store_removed_param('log_files', '8.1', FALSE);
  store_removed_param('log_simultaneous_copies', '8.1', FALSE);
  store_removed_param('log_small_entry_max_size', '8.1', FALSE);
  store_removed_param('mts_rate_log_size', '8.1', FALSE);
  store_removed_param('mts_rate_scale', '8.1', FALSE);
  store_removed_param('ogms_home', '8.1', FALSE);
  store_removed_param('ops_admin_group', '8.1', FALSE);
  store_removed_param('optimizer_search_limit', '8.1', FALSE);
  store_removed_param('parallel_default_max_instances', '8.1', FALSE);
  store_removed_param('parallel_min_message_pool', '8.1', FALSE);
  store_removed_param('parallel_server_idle_time', '8.1', FALSE);
  store_removed_param('parallel_server', '8.1', FALSE);
  store_removed_param('parallel_transaction_resource_timeout', '8.1', FALSE);
  store_removed_param('push_join_predicate', '8.1', FALSE);
  store_removed_param('reduce_alarm', '8.1', FALSE);
  store_removed_param('row_cache_cursors', '8.1', FALSE);
  store_removed_param('sequence_cache_entries', '8.1', FALSE);
  store_removed_param('shared_pool_reserved_min_alloc', '8.1', FALSE);
  store_removed_param('snapshot_refresh_interval', '8.1', FALSE);
  store_removed_param('snapshot_refresh_keep_connections', '8.1', FALSE);
  store_removed_param('snapshot_refresh_processes', '8.1', FALSE);
  store_removed_param('sort_direct_writes', '8.1', FALSE);
  store_removed_param('sort_read_fac', '8.1', FALSE);
  store_removed_param('sort_spacemap_size', '8.1', FALSE);
  store_removed_param('sort_write_buffer_size', '8.1', FALSE);
  store_removed_param('sort_write_buffers', '8.1', FALSE);
  store_removed_param('spin_count', '8.1', FALSE);
  store_removed_param('temporary_table_locks', '8.1', FALSE);
  store_removed_param('use_ism', '8.1', FALSE);

  -- Obsolete in 9.0.1
  store_removed_param('always_anti_join', '9.0.1', FALSE);
  store_removed_param('always_semi_join', '9.0.1', FALSE);
  store_removed_param('db_block_lru_latches', '9.0.1', FALSE);
  store_removed_param('db_block_max_dirty_target', '9.0.1', FALSE);
  store_removed_param('gc_defer_time', '9.0.1', FALSE);
  store_removed_param('gc_releasable_locks', '9.0.1', FALSE);
  store_removed_param('gc_rollback_locks', '9.0.1', FALSE);
  store_removed_param('hash_multiblock_io_count', '9.0.1', FALSE);
  store_removed_param('instance_nodeset', '9.0.1', FALSE);
  store_removed_param('job_queue_interval', '9.0.1', FALSE);
  store_removed_param('ops_interconnects', '9.0.1', FALSE);
  store_removed_param('optimizer_percent_parallel', '9.0.1', FALSE);
  store_removed_param('sort_multiblock_read_count', '9.0.1', FALSE);
  store_removed_param('text_enable', '9.0.1', FALSE);


  -- Obsolete in 9.2
  store_removed_param('distributed_transactions', '9.2', FALSE);
  store_removed_param('max_transaction_branches', '9.2', FALSE);
  store_removed_param('parallel_broadcast_enabled', '9.2', FALSE);
  store_removed_param('standby_preserves_names', '9.2', FALSE);

  -- Obsolete in 10.1 (mts_ renames commented out)
  store_removed_param('dblink_encrypt_login', '10.1', FALSE);
  store_removed_param('hash_join_enabled', '10.1', FALSE);
  store_removed_param('log_parallelism', '10.1', FALSE);
  store_removed_param('max_rollback_segments', '10.1', FALSE);
  store_removed_param('mts_listener_address', '10.1', FALSE);
  store_removed_param('mts_multiple_listeners', '10.1', FALSE);
  store_removed_param('mts_service', '10.1', FALSE);
  store_removed_param('optimizer_max_permutations', '10.1', FALSE);
  store_removed_param('oracle_trace_collection_name', '10.1', FALSE);
  store_removed_param('oracle_trace_collection_path', '10.1', FALSE);
  store_removed_param('oracle_trace_collection_size', '10.1', FALSE);
  store_removed_param('oracle_trace_enable', '10.1', FALSE);
  store_removed_param('oracle_trace_facility_name', '10.1', FALSE);
  store_removed_param('oracle_trace_facility_path', '10.1', FALSE);
  store_removed_param('partition_view_enabled', '10.1', FALSE);
  store_removed_param('plsql_native_c_compiler', '10.1', FALSE);
  store_removed_param('plsql_native_linker', '10.1', FALSE);
  store_removed_param('plsql_native_make_file_name', '10.1', FALSE);
  store_removed_param('plsql_native_make_utility', '10.1', FALSE);
  store_removed_param('row_locking', '10.1', FALSE);
  store_removed_param('serializable', '10.1', FALSE);
  store_removed_param('transaction_auditing', '10.1', FALSE);
  store_removed_param('undo_suppress_errors', '10.1', FALSE);

  -- Deprecated in 10.1, no new value
  store_removed_param('global_context_pool_size', '10.1', TRUE);
  store_removed_param('log_archive_start', '10.1', TRUE);
  store_removed_param('max_enabled_roles', '10.1', TRUE);

  -- Obsolete in 10.2
  store_removed_param('enqueue_resources', '10.2', FALSE);

  -- Deprecated, but not renamed in 10.2
  store_removed_param('serial_reuse', '10.2', TRUE);
  store_removed_param('sql_trace', '10.2', TRUE);

  -- Deprecated, but not renamed in 11.1
  store_removed_param('commit_write', '11.1', TRUE);
  store_removed_param('cursor_space_for_time', '11.1', TRUE);
  store_removed_param('instance_groups', '11.1', TRUE);
  store_removed_param('log_archive_local_first', '11.1', TRUE);
  store_removed_param('remote_os_authent', '11.1', TRUE);
  store_removed_param('standby_archive_dest', '11.1', TRUE);
  store_removed_param('plsql_v2_compatibility', '11.1', TRUE);

  -- Instead a new parameter diagnostic_dest is
  -- replace two (core_dump_dest lives)
  store_removed_param('background_dump_dest', '11.1', TRUE);
  store_removed_param('user_dump_dest', '11.1', TRUE);

  -- Obsolete in 11.1

  store_removed_param('_log_archive_buffer_size', '11.1', FALSE);
  store_removed_param('_fast_start_instance_recover_target', '11.1', FALSE);
  store_removed_param('_lm_rcv_buffer_size', '11.1', FALSE);
  store_removed_param('ddl_wait_for_locks', '11.1', FALSE);
  store_removed_param('remote_archive_enable', '11.1', FALSE);

  -- Deprecated in 11.2
  store_removed_param('active_instance_count', '11.2', TRUE);
  store_removed_param('cursor_space_for_time', '11.2', TRUE);
  store_removed_param('fast_start_io_target', '11.2', TRUE);
  store_removed_param('global_context_pool_size', '11.2', TRUE);
  store_removed_param('instance_groups', '11.2', TRUE);
  store_removed_param('lock_name_space', '11.2', TRUE);
  store_removed_param('log_archive_local_first', '11.2', TRUE);
  store_removed_param('resource_manager_cpu_allocation', '11.2', TRUE);
  store_removed_param('mts_circuits', '11.2', FALSE);
  store_removed_param('mts_dispatchers', '11.2', FALSE);
  store_removed_param('mts_max_dispatchers', '11.2', FALSE);
  store_removed_param('mts_max_servers', '11.2', FALSE);
  store_removed_param('mts_servers', '11.2', FALSE);
  store_removed_param('mts_sessions', '11.2', FALSE);

  -- Obsolete in 11.2
  store_removed_param('drs_start', '11.2', FALSE);
  store_removed_param('gc_files_to_locks', '11.2', FALSE);
  store_removed_param('plsql_native_library_dir', '11.2', FALSE);
  store_removed_param('plsql_native_library_subdir_count', '11.2', FALSE);
  store_removed_param('plsql_compiler_flags', '11.2', FALSE);
  store_removed_param('sql_version', '11.2', FALSE);
  store_removed_param('cell_partition_large_extents', '11.2', FALSE);

  -- Sessions removed for XE upgrade only
  IF db_is_XE THEN
    store_removed_param('sessions', '10.1', FALSE);
  END IF;

  --
  -- Removed for 12.1
  --
  store_removed_param('_lm_validate_resource_type', '12.1', TRUE);
  store_removed_param('sec_case_sensitive_logon', '12.1', TRUE);

  --
  -- Removed/Deprecated in 12.2
  /* At this time, 07_DICTIONARY_ACCESSIBILITY is the only upper case 
     parameter in v$parameter.*/
  store_removed_param('O7_DICTIONARY_ACCESSIBILITY', '12.2', TRUE);
  store_removed_param('utl_file_dir', '12.2', TRUE);
  store_removed_param('parallel_adaptive_multi_user','12.2', TRUE);
  store_removed_param('unified_audit_sga_queue_size', '12.2', TRUE);
  store_removed_param('_app_ctx_vers', '12.2', FALSE);
  store_removed_param('_average_dirties_half_life', '12.2', FALSE);
  store_removed_param('_aw_row_source_enabled', '12.2', FALSE);
  store_removed_param('_compatible_no_recovery', '12.2', FALSE);
  store_removed_param('_data_transfer_cache_size', '12.2', FALSE);
  store_removed_param('_db_no_mount_lock', '12.2', FALSE);
  store_removed_param('_dlm_send_timeout', '12.2', FALSE);
  store_removed_param('_dtree_bintest_id', '12.2', FALSE);
  store_removed_param('_dtree_compressbmp_enabled', '12.2', FALSE);
  store_removed_param('_evolve_plan_baseline_report_level', '12.2', FALSE);
  store_removed_param('_fast_start_instance_recovery_target', '12.2', FALSE);
  store_removed_param('_fic_max_length', '12.2', FALSE);
  store_removed_param('_fic_outofmem_candidates', '12.2', FALSE);
  store_removed_param('_idl_conventional_index_maintenance', '12.2', FALSE);
  store_removed_param('_kgl_latch_count', '12.2', FALSE);
  store_removed_param('_kks_free_cursor_stat_pct', '12.2', FALSE);
  store_removed_param('_kspptbl_mem_usage', '12.2', FALSE);
  store_removed_param('_lm_direct_sends', '12.2', FALSE);
  store_removed_param('_lm_multiple_receivers', '12.2', FALSE);
  store_removed_param('_lm_statistics', '12.2', FALSE);
  store_removed_param('_log_io_size', '12.2', FALSE);
  store_removed_param('_max_log_write_io_parallelism', '12.2', FALSE);
  store_removed_param('_module_action_old_length', '12.2', FALSE);
  store_removed_param('_optimizer_choose_permutation', '12.2', FALSE);
  store_removed_param('_oracle_trace_events', '12.2', FALSE);
  store_removed_param('_oracle_trace_facility_version', '12.2', FALSE);
  store_removed_param('_plan_verify_local_time_limit', '12.2', FALSE);
  store_removed_param('_plsql_conditional_compilation', '12.2', FALSE);
  store_removed_param('_px_async_getgranule', '12.2', FALSE);
  store_removed_param('_px_slaves_share_cursors', '12.2', FALSE);
  store_removed_param('_seq_process_cache_const', '12.2', FALSE);
  store_removed_param('_spr_use_hash_table', '12.2', FALSE);
  store_removed_param('_sqlexec_progression_cost', '12.2', FALSE);
  store_removed_param('_use_hidden_partitions', '12.2', FALSE);
  store_removed_param('_very_large_partitioned_table', '12.2', FALSE);
  store_removed_param('logmnr_max_persistent_sessions', '12.2', FALSE);
  store_removed_param('max_commit_propagation_delay', '12.2', FALSE);
  store_removed_param('optimizer_adaptive_features', '12.2', FALSE);
  store_removed_param('parallel_automatic_tuning', '12.2', FALSE);
  store_removed_param('parallel_degree_level', '12.2', FALSE);
  store_removed_param('parallel_io_cap_enabled', '12.2', FALSE);
  store_removed_param('exclude_seed_cdb_view', '12.2', FALSE);
  store_removed_param('_optimizer_adaptive_plans', '12.2', FALSE);
  store_removed_param('parallel_server_instances', '12.2', FALSE);
  store_removed_param('use_indirect_data_buffers', '12.2', FALSE);
  store_removed_param('asm_preferred_read_failure_groups', '12.2', TRUE);

  

  --
  -- Load Renamed parameters
  --

  -- Initialization Parameters Renamed in Release 8.0 --
  store_renamed_param('async_read','disk_asynch_io');
  store_renamed_param('async_write','disk_asynch_io');
  store_renamed_param('ccf_io_size','db_file_direct_io_count');
  store_renamed_param('db_file_standby_name_convert','db_file_name_convert');
  store_renamed_param('db_writers','dbwr_io_slaves');
  store_renamed_param('log_file_standby_name_convert',
                    'log_file_name_convert');
  store_renamed_param('snapshot_refresh_interval','job_queue_interval');

  -- Initialization Parameters Renamed in Release 8.1.4 --
  store_renamed_param('mview_rewrite_enabled','query_rewrite_enabled');
  store_renamed_param('rewrite_integrity','query_rewrite_integrity');

  -- Initialization Parameters Renamed in Release 8.1.5 --
  store_renamed_param('nls_union_currency','nls_dual_currency');
  store_renamed_param('parallel_transaction_recovery',
                    'fast_start_parallel_rollback');

  -- Initialization Parameters Renamed in Release 9.0.1 --
  store_renamed_param('fast_start_io_target','fast_start_mttr_target');
  store_renamed_param('mts_circuits','circuits');
  store_renamed_param('mts_dispatchers','dispatchers');
  store_renamed_param('mts_max_dispatchers','max_dispatchers');
  store_renamed_param('mts_max_servers','max_shared_servers');
  store_renamed_param('mts_servers','shared_servers');
  store_renamed_param('mts_sessions','shared_server_sessions');
  store_renamed_param('parallel_server','cluster_database');
  store_renamed_param('parallel_server_instances',
                    'cluster_database_instances');

  -- Initialization Parameters Renamed in Release 9.2 --
  store_renamed_param('drs_start','dg_broker_start');

  -- Initialization Parameters Renamed in Release 10.1 --
  store_renamed_param('lock_name_space','db_unique_name');

  -- Initialization Parameters Renamed in Release 10.2 --
  -- none as of 4/1/05

  -- Initialization Parameters Renamed in Release 11.2 --

  store_renamed_param('buffer_pool_keep', 'db_keep_cache_size');
  store_renamed_param('buffer_pool_recycle', 'db_recycle_cache_size');
  store_renamed_param('commit_write', 'commit_logging,commit_wait');

  --
  -- Initialize special initialization parameters
  --

  store_renamed_param_and_value('rdbms_server_dn',NULL,
                'ldap_directory_access','SSL');
  store_renamed_param_and_value('plsql_debug','TRUE',
                'plsql_optimize_level','1');

  --  Only use these special parameters for databases
  --  in which Very Large Memory is not enabled

  IF NOT db_VLM_enabled THEN
    store_renamed_param_and_value('db_block_buffers',NULL,
                  'db_cache_size',NULL);
    store_renamed_param_and_value('buffer_pool_recycle',NULL,
                  'db_recycle_cache_size',NULL);
    store_removed_param('db_block_buffers', '12.2', TRUE);
    store_removed_param('buffer_pool_keep', '11.2', TRUE);
  END IF;

  --
  -- for 12.1, AUDIT_TRAIL has deprecated several values
  -- that were allowed for AUDIT_TRAIL, they have new
  -- mappings.
  -- Use store_renamed_param_and_value  - bug  2631483 and set the
  -- dbua_outInUpdate flag so output_xml_initparams
  -- dumps these out
  --
  store_renamed_param_and_value('audit_trail','FALSE',
                    'audit_trail','NONE');
  store_renamed_param_and_value('audit_trail','TRUE',
                    'audit_trail','DB');
  store_renamed_param_and_value('audit_trail','DB_EXTENDED',
                    'audit_trail','DB,EXTENDED');


  --
  -- Min value for db_block_size
  --
  --store_required ('db_block_size', 2048, '', 3);

  --IF db_n_version = 102 THEN
    -- If undo_management is not specified in pre-11g database, then
    -- it needs to be specified MANUAL since the default is changing
    -- from MANUAL to AUTO starting in 11.1.
    -- store_required('undo_management', 0, 'MANUAL', 2);
  --END IF;

  -- for now, just compute memory recommendations for upgrades
  -- for non-cdb and ROOT.
  -- i.e., memory recommendations won't be listed in the
  -- pdb preupgrade_<pdb>.log for now.
  IF db_is_cdb = FALSE OR db_is_root = TRUE THEN
    init_mem_sizes(mem_parameters);
    find_mem_sizes(mem_parameters, is_show_mem_sizes);
  END IF;

  store_minval_param('processes', &C_DEFAULT_PROCESSES); -- brought forward from utluppkg

END init_parameters;

--
--    The following couple of functions are used in the computation of
--    tablespace info
--
-------------------------- ts_has_queues ---------------------------------
-- returns TRUE if there is at least one queue in the tablespace
FUNCTION ts_has_queues (tsname VARCHAR2) RETURN BOOLEAN
IS
  t_null CHAR(1);
BEGIN
  EXECUTE IMMEDIATE 'SELECT NULL FROM sys.dba_tables t
      WHERE EXISTS
      (SELECT 1 FROM sys.dba_queues q
         WHERE q.queue_table = t.table_name AND q.owner = t.owner)
      AND t.tablespace_name = :1 AND rownum <= 1'
      INTO t_null
      USING tsname;
    RETURN TRUE;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN RETURN FALSE;
END ts_has_queues;

-------------------------- ts_is_SYS_temporary ---------------------------------
-- returns TRUE if there is at least one queue in the tablespace

FUNCTION ts_is_SYS_temporary (tsname VARCHAR2) RETURN BOOLEAN
IS
  t_null CHAR(1);
BEGIN
  EXECUTE IMMEDIATE 'SELECT NULL FROM sys.dba_users
        WHERE username = ''SYS'' AND temporary_tablespace = :1'
    INTO t_null
    USING tsname;
  RETURN TRUE;
EXCEPTION
  WHEN NO_DATA_FOUND THEN RETURN FALSE;
END ts_is_SYS_temporary;


PROCEDURE init_resources
IS
  idx                 BINARY_INTEGER;
  tmp_cursor          cursor_t;
  tmp_num1            INTEGER;
  tmp_num2            INTEGER;
  delta_queues        INTEGER;
  delta_kbytes        INTEGER := 0;
  p_tsname            VARCHAR2(128);
  tmp_varchar1        VARCHAR2(128);
  tmp_varchar2        VARCHAR2(128);
  tmp_filename        SYS.DBA_TEMP_FILES.FILE_NAME%TYPE;
  p_status            VARCHAR2(30);
  sum_bytes           INTEGER;
  p_count             INTEGER;
  default_tablespaces VARCHAR2(4000);
  name                VARCHAR2(128);
  contents            VARCHAR2(128);
  temporary           BOOLEAN;
  localmanaged        BOOLEAN;
  inuse               INTEGER;
  alloc               INTEGER;
  auto                INTEGER;
  avail               INTEGER;
BEGIN
  --
  -- Misc stand-alone values we report about
  --
  pMinFlashbackLogGen  := 0;
  pMinArchiveLogGen    := 0;

  idx := 0;

  -- we know we need SYSTEM and SYSAUX in the list of tablespaces anyway, add 'em now.
  default_tablespaces := '''SYSTEM'', ''SYSAUX''';

  FOR i in 1..cmp_info.count LOOP
      IF (cmp_info(i).def_ts is not null) THEN
          -- there is not a worry about overflowing default_tablespaces or sql injection.  The values we pull from .def_ts
          -- are all hardcoded in this program, and as a result, we could just hardcode default_tablespaces too, but to
          -- make room for smooth changes in the future, this loop guarantees we pick up new def_ts's.  The current list
          -- as of 12.1.0.2 is only 'SYSTEM', 'SYSAUX'.

          -- push a new tablespace onto the list only if it doesn't exist on the list already
          IF (instr(default_tablespaces,'''' || cmp_info(i).def_ts || '''') = 0) THEN
              default_tablespaces := default_tablespaces || ',''' || cmp_info(i).def_ts || '''';
          END IF;
      END IF;
  END LOOP;

  OPEN tmp_cursor FOR
      'with 
       segments as (
         select  ds.tablespace_name, 
                 round(nvl(sum(ds.bytes) ,0)/:a,2)                                     as inuse 
         from sys.dba_segments ds
         group by ds.tablespace_name 
         ),
       ts_qresult as (
           SELECT dt.tablespace_name                                                   as name,
                  dt.contents                                                          as contents,
                  decode(dt.contents,''TEMPORARY'',1,0)                                as temporary,
                  decode(dt.extent_management,''LOCAL'',1,0)                           as localmanaged,
                  nvl(ds.inuse,0)                                                      as inuse,
                  nvl(round(sum(case dt.contents when ''TEMPORARY'' then 
                           dtf.bytes  
                     else  ddf.bytes end)/:b, 2),0)                                    as alloc, 
                  nvl(round(sum(case dt.contents when  ''TEMPORARY'' then 
                          decode(dtf.maxbytes, 0, 0, dtf.maxbytes-dtf.bytes)
                  else decode(ddf.maxbytes, 0, 0, ddf.maxbytes-ddf.bytes)end)/:c,2),0) as auto
           FROM   sys.dba_tablespaces    dt 
           left join      segments            ds on(dt.tablespace_name=ds.tablespace_name)
           left join sys.dba_data_files ddf on(ddf.tablespace_name=dt.tablespace_name)
           left join sys.dba_temp_files dtf on(dtf.tablespace_name=dt.tablespace_name)
           WHERE   (dt.tablespace_name in (:d,' || default_tablespaces || '))
           or      (dt.tablespace_name in (  SELECT distinct T.tablespace_name 
                                         FROM sys.dba_queues Q, sys.dba_tables T 
                                         WHERE Q.queue_table=T.table_name AND 
                                         Q.owner = T.owner)) 
           or      (dt.tablespace_name in (  SELECT temporary_tablespace 
                                         FROM sys.dba_users 
                                         WHERE username = ''SYS''))
           group by    dt.tablespace_name,
                       dt.contents,
                       dt.extent_management,
                       ds.inuse
           )
       select tq.name, tq.contents, tq.temporary, tq.localmanaged, tq.inuse, tq.alloc, tq.auto, tq.alloc+tq.auto avail 
       from ts_qresult tq order by tq.name'
  USING c_kb, c_kb, c_kb, db_undo_tbs; --:a :b :c :d
  LOOP
      FETCH tmp_cursor INTO name, contents, temporary, localmanaged, inuse, alloc, auto, avail;
      EXIT WHEN tmp_cursor%NOTFOUND;
      idx := idx + 1;
      ts_info(idx).temporary      := temporary;
      ts_info(idx).localmanaged   := localmanaged;
      ts_info(idx).name           := name;
      ts_info(idx).inuse          := inuse;
      ts_info(idx).alloc          := alloc;
      ts_info(idx).auto           := auto;
      ts_info(idx).avail          := avail;
      ts_info(idx).delta          := 0;
      ts_info(idx).inc_by         := 0;
      ts_info(idx).min            := 0;
      ts_info(idx).addl           := 0;
      ts_info(idx).contents       := contents;
  END LOOP;
  CLOSE tmp_cursor;

  -- max_ts := idx;   -- max tablespaces of interest

  -- *****************************************************************
  -- Collect Public Rollback Information
  -- *****************************************************************

  idx := 0;
  IF db_undo != 'AUTO' THEN  -- using rollback segments

    OPEN tmp_cursor FOR 
        'SELECT segment_name, next_extent, max_extents, status FROM SYS.dba_rollback_segs 
            WHERE owner=''PUBLIC'' OR (owner=''SYS'' AND segment_name != ''SYSTEM'')';
    LOOP
      FETCH tmp_cursor INTO tmp_varchar1, tmp_num1, tmp_num2, p_status;
      EXIT WHEN tmp_cursor%NOTFOUND;
      BEGIN
        --- get sum of bytes and tablespace name
        EXECUTE IMMEDIATE 
            'SELECT tablespace_name, sum(bytes) FROM sys.dba_segments 
                WHERE segment_name = :1  AND ROWNUM = 1 GROUP BY tablespace_name' 
        INTO p_tsname, sum_bytes
        USING tmp_varchar1;
        IF sum_bytes < c_kb THEN
          sum_bytes := 1;
        ELSE
          sum_bytes := sum_bytes/c_kb;
        END IF;
      EXCEPTION WHEN NO_DATA_FOUND THEN
        sum_bytes := NULL;
      END;

      IF sum_bytes IS NOT NULL THEN
        idx:=idx + 1;
        rs_info(idx).tbs_name := p_tsname;
        rs_info(idx).seg_name := tmp_varchar1;
        rs_info(idx).status   := p_status;
        rs_info(idx).next     := tmp_num1/c_kb;
        rs_info(idx).max_ext  := tmp_num2;
        rs_info(idx).inuse    := sum_bytes;
        EXECUTE IMMEDIATE 
          'SELECT ROUND(SUM(DECODE(maxbytes, 0, 0,maxbytes-bytes)/:1))
              FROM sys.dba_data_files WHERE tablespace_name=:2'
        INTO rs_info(idx).auto
        USING c_kb, p_tsname;

        EXECUTE IMMEDIATE 
          'SELECT ROUND(SUM(DECODE(maxbytes, 0, 0,maxbytes-bytes)/:1))
              FROM sys.dba_data_files WHERE tablespace_name=:2'
        INTO tmp_num1
        USING c_kb, p_tsname;
      END IF;
    END LOOP;
    CLOSE tmp_cursor;
  END IF;  -- using undo tablespace, not rollback

  -- max_rs := idx;

  -- *****************************************************************
  -- Determine free space needed if
  --   Archiving was on; 
  --   Flashback Database was on
  -- We only report the values if they are actually on.
  -- *****************************************************************

  -- calculate the minimum amount of archive and flashback logs used 
  -- for an upgrade for each component. 
  --
  find_archive_dest_info();
  find_recovery_area_info();

  -- Total recovery area needed is:
  --   pMinArchiveLogGen + pMinFlashbacklogGen;

  -- *****************************************************************
  -- Collect Flashback Information
  -- *****************************************************************

  -- initialize flashback_info
  flashback_info.active := FALSE;
  flashback_info.name := '';
  flashback_info.limit := 0;
  flashback_info.used := 0;
  flashback_info.reclaimable := 0;
  flashback_info.files := 0; 
  flashback_info.file_dest := '';
  flashback_info.dsize := 0;

  flashback_info.active := db_flashback_on;  -- is flashback active? T/F
  
  IF db_fra_set = TRUE THEN
    --
    -- Get the rest of the flashback settings
    -- 

    BEGIN
      EXECUTE IMMEDIATE 'SELECT rfd.name, rfd.space_limit, rfd.space_used, 
                  rfd.space_reclaimable, rfd.number_of_files,
                  vp1.value, vp2.value 
        FROM v$recovery_file_dest rfd, v$parameter vp1, v$parameter vp2
        WHERE UPPER(vp1.name) = ''DB_RECOVERY_FILE_DEST'' AND
               UPPER(vp2.name) = ''DB_RECOVERY_FILE_DEST_SIZE'''
       INTO flashback_info.name, flashback_info.limit, flashback_info.used,
              flashback_info.reclaimable, flashback_info.files, 
              flashback_info.file_dest, flashback_info.dsize;
      EXCEPTION
        WHEN NO_DATA_FOUND THEN flashback_info.active := FALSE;
    END;
  END IF;

  -- *****************************************************************
  -- Calculate Tablespace Requirements
  -- *****************************************************************

  -- Look at all relevant tablespaces
  -- TS: loop per tablespace (ts_info(t).name)
  FOR t IN 1..ts_info.count LOOP
    delta_kbytes:=0;   -- initialize calculated tablespace delta

    IF ts_info(t).name = 'SYSTEM' THEN -- sum the component SYS kbytes
      FOR i IN 1..cmp_info.count LOOP

        IF pDBGSizeResources THEN
          IF cmp_info(i).processed THEN
            DisplayDiagLine (cmp_info(i).cid || ' Processed. ' || ' Default Tblspace ' || cmp_info(i).def_ts || '.');
          ELSE
            DisplayDiagLine (cmp_info(i).cid || ' NOT Processed.');
          END IF;
        END IF;

        IF cmp_info(i).processed THEN
          IF cmp_info(i).install THEN  -- if component will be installed
            delta_kbytes := delta_kbytes + cmp_info(i).ins_sys_kbytes;
            IF pDBGSizeResources THEN
              DisplayDiagLine ('SYSTEM ' || 
                  LPAD(cmp_info(i).cid, 10) || ' ToBeInstalled ' ||
                  LPAD(cmp_info(i).ins_sys_kbytes/c_kb,10) || 'Mb'); 
            END IF;
          ELSE  -- if component is already in the registry
            delta_kbytes := delta_kbytes + cmp_info(i).sys_kbytes;
            IF pDBGSizeResources THEN
              DisplayDiagLine ('SYSTEM ' || 
                     LPAD(cmp_info(i).cid, 10) || ' IsInRegistry ' ||
                     LPAD(cmp_info(i).sys_kbytes/c_kb,10) || 'Mb');
            END IF;
          END IF;
        END IF;  -- nothing to add if component is or will not be in
                 -- the registry
      END LOOP;

    END IF;  -- end of special SYSTEM tablespace processing
    -- TS: delta after looping through components in SYSTEM

    IF ts_info(t).name = 'SYSAUX' THEN -- sum the component SYSAUX kbytes
      FOR i IN 1..cmp_info.count LOOP
        IF cmp_info(i).processed AND
              (cmp_info(i).def_ts = 'SYSAUX' OR
               cmp_info(i).def_ts = 'SYSTEM') THEN
          IF cmp_info(i).sysaux_kbytes >= cmp_info(i).def_ts_kbytes THEN
            delta_kbytes := delta_kbytes + cmp_info(i).sysaux_kbytes;
          ELSE
            delta_kbytes := delta_kbytes + cmp_info(i).def_ts_kbytes;
          END IF;
          IF pDBGSizeResources THEN
            DisplayDiagLine('SYSAUX ' || 
                   LPAD(cmp_info(i).cid, 10) || ' ' ||
                   LPAD(cmp_info(i).sysaux_kbytes/c_kb,10) || 'Mb');
          END IF;
          -- bug 13060071 :  apex , xdb
          -- if xdb and apex are both in db, then add 316M-85M (or 231M
          -- more) to sysaux if xdb resides here
          IF (cmp_info(i).cid = 'XDB'
              AND cmp_info(apex).processed = TRUE) THEN
            delta_kbytes :=  delta_kbytes + (231*c_kb);
            IF pDBGSizeResources THEN
              DisplayDiagLine('SYSAUX ' || 
                  LPAD(cmp_info(i).cid, 10) || ' ' || '(due to APEX) ' ||
                  LPAD(231, 10) || 'Mb');
            END IF;
          END IF;
        END IF;
      END LOOP;
    END IF;  -- end of special SYSAUX tablespace processing
    -- TS: sum delta for components in SYSAUX

    -- For tablespaces that are not SYSTEM:
    -- For tablespaces that are not SYSAUX:
    -- For tablespaces that are not UNDO:
    -- Now add in component default tablespace deltas
    -- def_tablespace_name is NULL for unprocessed comps

    IF (ts_info(t).name != 'SYSTEM' AND
        ts_info(t).name != 'SYSAUX' AND
        ts_info(t).name != db_undo_tbs) THEN
      FOR i IN 1..cmp_info.count LOOP 
        IF (ts_info(t).name = cmp_info(i).def_ts AND
           cmp_info(i).processed) THEN
          IF cmp_info(i).install THEN  -- use install amount
            delta_kbytes := delta_kbytes + cmp_info(i).ins_def_kbytes;
            IF pDBGSizeResources THEN
              DisplayDiagLine( RPAD(ts_info(t).name, 10) ||
                           LPAD(cmp_info(i).cid, 10) || ' ' ||
                           LPAD(cmp_info(i).ins_def_kbytes,10));   
            END IF;

          ELSE  -- use default tablespace amount
            -- bug 9664514
            -- if apex version in the source db is older than the version
            -- in target db, then apex upgrade include apex install;
            -- estimate 180M for typical apex install.
            -- note: this section is for space calculations for
            -- tablespaces that are non-system and non-sysaux
            delta_kbytes :=  delta_kbytes + cmp_info(i).def_ts_kbytes;

            IF pDBGSizeResources THEN
              DisplayDiagLine(RPAD(ts_info(t).name, 10) ||
                      LPAD(cmp_info(i).cid, 10) || ' ' ||
                      LPAD(cmp_info(i).def_ts_kbytes/c_kb, 10) || 'Mb');
              --update_puiu_data('SCHEMA', 
              --   ts_info(t).name || '-' || cmp_info(i).schema,
              --   cmp_info(i).def_ts_kbytes);
            END IF;
          END IF;

          -- bug 13060071 :  apex , xdb
          -- if xdb and apex are both in db, then add 316M-85M (or 231M
          -- more) to xdb default tablespace
          IF (cmp_info(i).cid = 'XDB' AND
              cmp_info(apex).processed = TRUE) THEN
            delta_kbytes :=  delta_kbytes + (231*c_kb);
            IF pDBGSizeResources THEN
              DisplayDiagLine(RPAD(ts_info(t).name, 10) || ' ' ||
                        LPAD(cmp_info(i).cid, 10) || ' ' ||
                        '(due to APEX) ' || LPAD(231, 10) || 'Mb');
            END IF;
          END IF;
        END IF;
      END LOOP; -- end of default tablespace calculations 
    END IF; -- end of if tblspace is not undo and not sysaux and not system
            -- then add in component default tablespace deltas

    -- TS: sum delta for install in default tablespaces other than
    --          SYSAUX

    -- For tablespaces that are not undo:
    -- Now look for queues in user schemas
    IF ts_info(t).name != db_undo_tbs THEN
      EXECUTE IMMEDIATE 'SELECT count(*) FROM sys.dba_tables tb, sys.dba_queues q
          WHERE q.queue_table = tb.table_name AND
               tb.tablespace_name = '' || ts_info(t).name || '' AND tb.owner NOT IN
                (''SYS'',''SYSTEM'',''MDSYS'',''ORDSYS'',''OLAPSYS'',''XDB'',
                ''LBACSYS'',''CTXSYS'',''ODM'',''DMSYS'', ''WKSYS'',''WMSYS'',
                 ''SYSMAN'',''EXFSYS'') '
      INTO delta_queues;

      IF delta_queues > 0 THEN
        delta_kbytes := delta_kbytes + delta_queues*48; 
        IF pDBGSizeResources THEN
          DisplayDiagLine(RPAD(ts_info(t).name, 10) ||
                  ' QUEUE count = ' || delta_queues);
        END IF;
      END IF;
    END IF;  -- end of if tablespace is not undo
             -- then look for queues in user schemas

    -- See if this is the temporary tablespace for SYS
    IF ts_is_SYS_temporary(ts_info(t).name) THEN
    	-- setting the minimum amount for the sys temp tablespace
      	delta_kbytes := c_temp_minsz_kb;
    END IF;

    -- See if this is the UNDO tablespace - be sure at least
    -- 400M (or c_undo_minsz_kb) is available
    IF ts_info(t).name = db_undo_tbs THEN
      ts_info(t).min := c_undo_minsz_kb;
      IF ts_info(t).alloc < ts_info(t).min THEN
        delta_kbytes := ts_info(t).min - ts_info(t).inuse;
      ELSE
        delta_kbytes := 0;
      END IF;
    END IF;  -- end of if this is the undo tablespace

    IF NOT cmp_info(em).processed THEN
      IF ts_info(t).name = 'SYSTEM' THEN 
        delta_kbytes := delta_kbytes + cmp_info(em).ins_sys_kbytes;
      ELSIF ts_info(t).name = 'SYSAUX' THEN
        delta_kbytes := delta_kbytes + cmp_info(em).ins_def_kbytes;
      END IF;
    END IF;

    -- Put a 20% safety factor on DELTA and round it off
    delta_kbytes := ROUND(delta_kbytes*1.20);            

    -- Finally, save DELTA value
    ts_info(t).delta := delta_kbytes;

    -- Calculate here the recommendation for minimum tablespace size - it is
    -- the "delta" plus existing in use amount IF tablespace is not undo.
    -- Else if tablespace is undo, then minimum was already set above
    -- to 400M (or c_undo_minsz_kb); therefore no need to calculate here.

    -- calculate ts_info(t).min
    IF ts_info(t).name != db_undo_tbs THEN
      -- calculate minimum tablespace size IF tablespace is NOT undo
      ts_info(t).min := ts_info(t).inuse + ts_info(t).delta;

      -- See if this is the SYSAUX tablespace - be sure at least 500M allocated
      IF ts_info(t).name = 'SYSAUX' THEN
        IF ts_info(t).min < c_sysaux_minsz_kb THEN
          ts_info(t).min := c_sysaux_minsz_kb;
        END IF;
      END IF;  -- end of checking that the minimum required space for SYSAUX
               -- is at least 500Mb (or c_sysaux_minsz_kb)

    END IF;  -- end of calculate ts_info(t).min 

    -- convert to MB and round up(min required)/down (alloc,avail,inuse)
    ts_info(t).min :=   CEIL(ts_info(t).min/c_kb);
    ts_info(t).alloc := ROUND((ts_info(t).alloc+511)/c_kb);
    ts_info(t).avail := ROUND((ts_info(t).avail-512)/c_kb);
    ts_info(t).inuse := ROUND((ts_info(t).inuse)/c_kb);

    -- Determine amount of additional space needed
    -- independent of autoextend on/off
    --

    IF ts_info(t).min > ts_info(t).alloc THEN
      ts_info(t).addl  := ts_info(t).min - ts_info(t).alloc;
    ELSE
      ts_info(t).addl := 0;
    END IF;

    -- Do we have enough space in the existing tablespace?
    IF ts_info(t).min <= ts_info(t).avail  THEN
      ts_info(t).inc_by := 0;
    ELSE
       -- need to add space
       ts_info(t).inc_by := ts_info(t).min - ts_info(t).avail; 

    END IF;

    -- Find at least one file in the tablespace with autoextend on.
    -- If found, then that tablespace has autoextend on; else not on.
    -- DBUA will use this information to add to autoextend
    -- or to check for total space on disk
    --
    IF ts_info(t).addl > 0 OR ts_info(t).inc_by > 0 THEN
      ts_info(t).fauto := FALSE;
      IF ts_info(t).temporary AND  ts_info(t).localmanaged THEN
        OPEN tmp_cursor FOR 
             'SELECT file_name, autoextensible from sys.dba_temp_files ' ||
             'where tablespace_name = :1' using ts_info(t).name;
      ELSE
        OPEN tmp_cursor FOR
             'SELECT file_name, autoextensible from sys.dba_data_files ' ||
             'where tablespace_name = :1' using ts_info(t).name;
      END IF;
      LOOP
        FETCH tmp_cursor INTO tmp_filename, tmp_varchar2; EXIT WHEN tmp_cursor%NOTFOUND;
        IF tmp_varchar2 = 'YES' THEN
          ts_info(t).fname := tmp_filename;
          ts_info(t).fauto := TRUE;
          EXIT;
        END IF;
      END LOOP;
      CLOSE tmp_cursor;
    END IF;

    -- Cursor to determine if UNDO tablespace is autextensible even if 
    -- it was enough space for the upgrade.
    IF (ts_info(t).contents='UNDO' and (ts_info(t).addl = 0 OR ts_info(t).inc_by = 0)) THEN
        ts_info(t).fauto := FALSE;
        OPEN tmp_cursor FOR
             'SELECT file_name, autoextensible from sys.dba_data_files ' ||
             'where tablespace_name = :1' using ts_info(t).name;
      LOOP
        FETCH tmp_cursor INTO tmp_filename, tmp_varchar2;
        EXIT WHEN tmp_cursor%NOTFOUND;
        IF tmp_varchar2 = 'YES' THEN
          ts_info(t).fname := tmp_filename;
          ts_info(t).fauto := TRUE;
          EXIT;
        END IF;
      END LOOP;
        CLOSE tmp_cursor;
    END IF;
  END LOOP;  -- end of tablespace loop

END init_resources;


-- ****************************************************************************
-- if run from the root, return total # of pdbs (including seed) in the cdb
-- if run from the pdb, then return 1
-- if this db is not a cdb or # of pdbs cannot be found, then return 0
-- note: we are just returning the total # of pdbs as see from v$pdbs
--       i.e., for now, not looking at status, etc of the pdbs 
-- ****************************************************************************
FUNCTION get_npdbs RETURN NUMBER
IS
  nPdbs   NUMBER := 0;
  e_noTblFound EXCEPTION;   -- ORA-00942: table or view does not exist
  PRAGMA exception_init(e_noTblFound, -942);
BEGIN
  begin
    execute immediate
      'select count(*) from sys.v$pdbs'
      into nPdbs;
  exception
    WHEN e_noTblFound THEN nPdbs := 0;
  end;

  return nPdbs;
END get_npdbs;


-- ****************************************************************************
-- init_mem_sizes
-- This is called from init_parameters
-- We're here because we need to initialize min values for memory sizes
-- for upgrade.
-- Note: For cdb upgrades, we are sizing for:
--       a) default -n and -N of catctl.pl 
--       b) as if all the pdbs will be upgraded with the root
-- Note: Only display memory sizing recommendations for non-cdb and ROOT, not
--       PDBs.
-- ****************************************************************************
PROCEDURE init_mem_sizes (memvp IN OUT MEMPARAMETER_TABLE_T)
IS
  extra       NUMBER;
  minvalue    NUMBER;  -- minimum value to set
  pdbs_para   NUMBER;  -- at most # of pdbs upgrading in parallel at a time
  batches     NUMBER;  -- approximate # of pdb upgrade "cycles"
  name_idx    V$PARAMETER.NAME%TYPE;
BEGIN
  
  BEGIN
    -- create mem_parameters records and initialize the min values to 0MB
    -- note: although we are not making minium recommendations for large pool
    --       and stream pool, we still need their values (if user-set) for
    --       sga_target calculation
  
    store_memparam_record(cs_idx, 0, memvp);  -- db_cache_size
    store_memparam_record(jv_idx, 0, memvp);  -- java_pool_size
    store_memparam_record(sp_idx, 0, memvp);  -- shared_pool_size
    store_memparam_record(lp_idx, 0, memvp);  -- large_pool_size
    store_memparam_record(sr_idx, 0, memvp);  -- streams_pool_size
    store_memparam_record(pt_idx, 0, memvp);  -- pga_aggregate_target
    store_memparam_record(st_idx, 0, memvp);  -- sga_target
    store_memparam_record(mt_idx, 0, memvp);  -- memory_target
  END;

  extra := 0;

  -- db_cache_size
  IF db_cpus <= 3 THEN
    memvp(cs_idx).min_value := 48 * c_mb;
  ELSE
    memvp(cs_idx).min_value := (4 * db_cpus) * c_mb;
  END IF;

  -- large pool size
  memvp(lp_idx).min_value := (8 * db_cpus) * c_mb;

  -- streams_pool_size
  memvp(sr_idx).min_value := 0;  -- 0M

  IF db_is_cdb = FALSE THEN  -- this db is a non-cdb
    -- java_pool_size
    memvp(jv_idx).min_value := 100 * c_mb;

    -- shared_pool_size
    -- (RTI 18990952 [lrgcu44bdbua]: 472M shared pool was not enough on
    --  AIX.PPC64 upgrading 11.2.0.4 to 12.2. 660M worked.)
    extra := (264 * 1.5) * c_mb;  -- 396Mb
    memvp(sp_idx).min_value := 264 * c_mb + extra;  -- 660Mb
    extra := 0;

    -- pga_aggregate_target
    memvp(pt_idx).min_value := 384 * c_mb;

  ELSE  -- IF db is a cdb
    -- find # of pdbs that at most will be upgrading at a time.
    -- using the default as defined in catctl.pl.
    -- will size for default, which is at most smallest integer of cpu_count/2
    -- of pdbs upgrading at a time.
    -- for example,
    --   if cdb has 33 pdbs and # of cpus is 32, then pdbs_para=32/2=16
    IF db_n_pdbs >= trunc(db_cpus/2) THEN  -- if # of pdbs >= (# of cpus/2)
      IF db_cpus = 1 THEN
        -- on 1 cpu mach, default is at most 1 pdb upgrading in parallel
        pdbs_para := 1;
      ELSE
        pdbs_para := trunc(db_cpus/2);
      END IF;
    ELSE    -- if # of pdbs < (# of cpus/2)
      -- if we know there's more cpus/2 on this system than pdbs, then lets
      -- just size for a smaller # of pdbs upgrading in parallel (pdbs_para).
      -- e.g., cdb has 10 pdbs and # of cpus is 32, then size for pdbs_para=10.
      pdbs_para := db_n_pdbs;
    END IF;

    -- for example, if upgrading 16 pdbs at a time,
    -- then if total # of pdbs is 32, it's 2 pdb cycles
    -- then if total # of pdbs is 33, it's 3 pdb cycles
    batches := ceil(db_n_pdbs/pdbs_para);  -- estimated # of pdb upgrade cycles

    -- java pool needed is 64M per pdb upgrading in a batch
    extra := 50 * c_mb;
    memvp(jv_idx).min_value := (64 * pdbs_para) * c_mb + extra;
    extra := 0;

    memvp(sp_idx).min_value := 
      (  (264 * 3)
       + (264 * 2)
       + (pdbs_para * 200)
       + (db_n_pdbs * 20)
       + (batches * 35)
      ) *  c_mb;
      --   constant in con id 1
      -- + constant/reserve in con id 0
      -- + reserve 200M of shared pool during pdb upgrade in pdb con id
      -- + up to 20m of misc in pdb con id that has been upgraded or opened
      -- + extra

    -- pga_aggregate_target
    memvp(pt_idx).min_value := 1152 * c_mb;

  END IF;  -- IF db is a cdb

  memvp(st_idx).min_value :=
    memvp(cs_idx).min_value + memvp(jv_idx).min_value +
    memvp(sp_idx).min_value + memvp(lp_idx).min_value +
    memvp(sr_idx).min_value;

  memvp(mt_idx).min_value :=
    memvp(cs_idx).min_value + memvp(jv_idx).min_value +
    memvp(sp_idx).min_value + memvp(lp_idx).min_value +
    memvp(sr_idx).min_value + memvp(pt_idx).min_value;

END init_mem_sizes;


--------------------------- find_mem_sizes ------------------------------
-- Find minimum sizes for memory parameters needed for upgrades.
-- IN/OUT: memory_parameters => memvp
-- IN/OUT: is_show_mem_sizes => display_min_mem_sizes
--
PROCEDURE find_mem_sizes (memvp                 IN OUT MEMPARAMETER_TABLE_T,
                          display_min_mem_sizes IN OUT BOOLEAN)
IS
  extra         NUMBER;
  is_db_noncdb  BOOLEAN;      -- is db a non-cdb?  TRUE if yes/FALSE if not
  name_idx      V$PARAMETER.NAME%TYPE;
BEGIN
 
  IF db_is_cdb = TRUE THEN
    is_db_noncdb := FALSE;
  ELSE
    is_db_noncdb := TRUE;
  END IF;

  -- For 11.1 and up check if MEMORY_TARGET is set and NON-ZERO 
  -- 
  -- check sga_target + pga_target (for cases where SGA_TARGET is in use)
  --
  -- memory_target in use
  -- if memory_target's oldvalue is not 0, then...
  IF memvp(mt_idx).old_value != 0 THEN
    find_sga_mem_values(memvp);

    -- If the newvalue is greater than the old value set the display TRUE
    IF memvp(mt_idx).new_value > memvp(mt_idx).old_value THEN
      memvp(mt_idx).display := TRUE;
    END IF;

    -- Loop through other pool sizes to ignore warnings
    --
    -- If a minimum value is required for MEMORY_TARGET then
    -- do not output a minimum value for sga_target, pga_aggregate_target,
    -- shared_pool_size, java_pool_size, db_cache_size, 
    -- large_pool_size, and streams_pool_size as these values
    -- are no longer considered once MEMORY_TARGET value is set.
    -- i.e., for params listed above, set display to FALSE if memory_target
    -- is set.
    --
    -- do not replace memory_target's newvalue with minvalue
    name_idx := memvp.first;
    WHILE name_idx IS NOT NULL LOOP
      IF (memvp(name_idx).name
            NOT IN (mt_idx,st_idx,pt_idx,sp_idx,jv_idx,cs_idx,lp_idx,sr_idx))
         AND
         (memvp(name_idx).old_value IS NULL
            OR memvp(name_idx).old_value < memvp(name_idx).min_value)
      THEN
        memvp(name_idx).display := TRUE;
        memvp(name_idx).new_value := memvp(name_idx).min_value;
      END IF;
      name_idx := memvp.next(name_idx);
    END LOOP;     

  ELSIF memvp(st_idx).old_value != 0 THEN  -- SGA_TARGET in use
    find_sga_mem_values(memvp);

    IF memvp(st_idx).new_value > memvp(st_idx).old_value THEN
      memvp(st_idx).display := TRUE;
    END IF;

    -- do not set display to TRUE for these params:
    --   memory_target, db_cache_size, java_pool_size,
    --   shared_pool_size, large_pool_size, and streams_pool_size
    -- do not replace sga_target's newvalue with minvalue
    name_idx := memvp.first;
    WHILE name_idx IS NOT NULL LOOP
      IF (memvp(name_idx).name
            NOT IN (st_idx,mt_idx,cs_idx,jv_idx,sp_idx,lp_idx,sr_idx))
         AND 
         (memvp(name_idx).old_value IS NULL
            OR memvp(name_idx).old_value < memvp(name_idx).min_value)
      THEN
        memvp(name_idx).display := TRUE;
        memvp(name_idx).new_value := memvp(name_idx).min_value;
      END IF;
      name_idx := memvp.next(name_idx);
    END LOOP;

  ELSE -- only pool sizes are used
    name_idx := memvp.first;
    WHILE name_idx IS NOT NULL LOOP
      -- don't print recommendations for sga_target, memory_target,
      -- large_pool_size, and streams_pool_size
      IF (memvp(name_idx).name NOT IN (st_idx,mt_idx,lp_idx,sr_idx))
         AND 
         (memvp(name_idx).old_value IS NULL
            OR memvp(name_idx).old_value < memvp(name_idx).min_value)
      THEN
        memvp(name_idx).display := TRUE;
        memvp(name_idx).new_value := memvp(name_idx).min_value;
      END IF;
      name_idx := memvp.next(name_idx);
    END LOOP;
  END IF;  -- end of if memory_target, if sga_target, or if neither is in use

  --
  -- for those memory size parmeters outside of memory_target/sga_target
  -- that won't be recommended, explicitly set DISPLAY to FALSE here (even
  -- if some had already been set to FALSE above)
  --
  --  we do not make recommendations for:
  memvp(lp_idx).display := FALSE;  -- large pool
  memvp(sr_idx).display := FALSE;  -- streams pool
  memvp(pt_idx).display := FALSE;  -- pga aggregate target

  -- now copy the info from mem_parameters to all_parameters.
  -- since all_parameters is only displaying the min_value variable for 
  -- memory recommendations, then just copy over mem_parameters' new_value to
  -- all_parameters' min_value.
  -- only copy the pool sizes that we want to be displayed.
  -- ^^^ Note: for now, only copy the memory info for non-cdb and ROOT (no PDB)
  --           because we don't want these values to be displayed for PDBs
  IF is_db_noncdb = TRUE OR db_is_root = TRUE THEN 
    name_idx := memvp.first;
    WHILE name_idx IS NOT NULL LOOP
      IF memvp(name_idx).display = TRUE THEN
        all_parameters(name_idx).min_value := memvp(name_idx).new_value;
        display_min_mem_sizes := TRUE;  -- there will be at least 1 minimum
                                        -- memory size to display
      END IF;
      name_idx := memvp.next(name_idx);
    END LOOP;
  END IF;

END find_mem_sizes;


--------------------------- find_sga_mem_values ------------------------------
-- This is called when sga_target or memory_target is used.

PROCEDURE find_sga_mem_values (memvp IN OUT MEMPARAMETER_TABLE_T)
IS
  extra       NUMBER;
  mtgval      NUMBER;
BEGIN

  -- We're here because sga_target/memory_target is used.
  -- Need to find new values for sga_target.

  -- First, reset min values for pools/memory related to sga_target

  -- buffer cache (cs)
  IF memvp(cs_idx).old_value > memvp(cs_idx).min_value THEN
    memvp(cs_idx).dif_value :=
      memvp(cs_idx).old_value - memvp(cs_idx).min_value;
  END IF;

  -- java pool (jv)
  IF memvp(jv_idx).old_value > memvp(jv_idx).min_value THEN
    memvp(jv_idx).dif_value :=
      memvp(jv_idx).old_value - memvp(jv_idx).min_value;
  END IF;

  -- shared pool (sp)
  IF memvp(sp_idx).old_value > memvp(sp_idx).min_value THEN
    memvp(sp_idx).dif_value :=
      memvp(sp_idx).old_value - memvp(sp_idx).min_value;
  END IF;

  -- large pool (lp)
  IF memvp(lp_idx).old_value > memvp(lp_idx).min_value THEN
    memvp(lp_idx).dif_value :=
      memvp(lp_idx).old_value - memvp(lp_idx).min_value;
  END IF;

  -- streams pool (sr)
  IF memvp(sr_idx).old_value > memvp(sr_idx).min_value THEN
    memvp(sr_idx).dif_value :=
      memvp(sr_idx).old_value - memvp(sr_idx).min_value;
  END IF;

  -- pga_aggregate_target (pt)
  IF memvp(pt_idx).old_value > memvp(pt_idx).min_value THEN
    memvp(pt_idx).dif_value :=
      memvp(pt_idx).old_value - memvp(pt_idx).min_value;
  END IF;

  -- calculate sga_target 'newvalue' (new derived minimum) based on
  -- st_idx.min_value and user-specified pool sizes.
  -- need to add extra memory or db may not start in new release due to:
  -- ORA-00821: Specified value of sga_target <value> is too small,
  memvp(st_idx).new_value := 
      memvp(st_idx).min_value + memvp(cs_idx).dif_value
      + memvp(jv_idx).dif_value + memvp(sp_idx).dif_value
      + memvp(lp_idx).dif_value + memvp(sr_idx).dif_value
      + (128 * c_mb);

  -- calculate memory_target 'newvalue' (new derived minimum) based on
  -- mt_idx.min_value and user-specified pool sizes.
  -- need to add extra memory or db may not start in new release due to:
  -- ORA-00838: Specified value of MEMORY_TARGET is too small...
  memvp(mt_idx).new_value :=
    memvp(mt_idx).min_value + memvp(cs_idx).dif_value
    + memvp(jv_idx).dif_value + memvp(sp_idx).dif_value
    + memvp(lp_idx).dif_value + memvp(sr_idx).dif_value
    + memvp(pt_idx).dif_value + (256 * c_mb);

  IF (memvp(st_idx).old_value != 0) THEN -- SGA_TARGET in use
    -- calculate 'newvalue' (new derived minimum) based on user-set sga_target
    -- and user-set pga_aggregate_target.
    -- for memory_target if sga_target is also set.
    -- add extra memory to ensure db will open in new release.
    mtgval := memvp(st_idx).old_value + memvp(pt_idx).old_value + 128*c_mb;
    -- set 'newvalue' to the larger of the two new derived minimums (see above)
    IF (mtgval > memvp(mt_idx).new_value) THEN
      memvp(mt_idx).new_value := mtgval;
    END IF;
  END IF;

  -- Note: Although sga_target and memory_target values are found here, we
  -- don't set DISPLAY in memvp in this procedure.  This setting is done
  -- in find_mem_sizes.

END find_sga_mem_values;


--
-- is current container CDB$ROOT?
-- if db is a cdb and current container connected to is root, return TRUE.
-- else return FALSE.
--
FUNCTION is_con_root RETURN BOOLEAN
IS
  b_isCdb    BOOLEAN  := FALSE;
  b_retStat  BOOLEAN  := FALSE;
  conId      NUMBER;
BEGIN
  IF db_is_cdb = FALSE THEN -- this db is a non-cdb
    b_retStat := FALSE;  -- no, it can't be the ROOT
  ELSE  -- this db is a cdb
    conId := sys.dbms_preup.get_con_id;  -- check con id
    IF (conId = 1) THEN  -- ROOT's con id is 1
      b_retStat := TRUE;  -- yes, current container is CDB$ROOT
    END IF;
  END IF;
  return b_retStat;
END is_con_root;


--
-- is SIZE-ing THIS MEMory PARAMeter for upgrade?
-- if yes, return TRUE else return FALSE.
-- note: if that parameter's value will not be displayed, its
--        mem_parameters.display would have been set to FALSE
FUNCTION  is_size_this_memparam (name V$PARAMETER.NAME%TYPE) RETURN BOOLEAN
IS
BEGIN

  -- these are the parameters we size or use for sizing for memory
  IF (name IN (cs_idx, jv_idx, sp_idx, lp_idx, sr_idx, pt_idx, st_idx, mt_idx))
  THEN
    return TRUE;
  END IF;

  return FALSE;
END is_size_this_memparam;


-- *****************************************************************
--     find_all_pdb_archive_size
--  o return estimated minimum amount of archivelog size to be generated
--    for all pdbs.
-- *****************************************************************
FUNCTION find_all_pdb_archive_size RETURN NUMBER
IS
  check_stmt_0           VARCHAR2(500);    -- check sql stmt to build on
  check_stmt             VARCHAR2(1000);   -- sql stmt to run
  rowcount               NUMBER := 0;      -- number of rows returned
  i                      NUMBER := 0;      -- loop counter
  min_pdb_archivelog_gen NUMBER := 0;      -- estimated minimum amount of
                                           -- archivelog to be generated in pdbs
BEGIN

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: begin of find_all_pdb_archive_size');
  END IF;

  check_stmt_0 := 
    'SELECT count(*) FROM sys.cdb_registry ' ||
    '  WHERE namespace =''SERVER'' AND CON_ID <> 2 AND comp_id = ';

  --
  -- because each pdb may have a subset of root's components...
  -- for each "processed" component in the registry for ROOT
  --   o find the # of pdbs that has this component
  --   o since seed may not be in cdb_registry, assume root's components are
  --     same as seed
  --   o if apex is in registry but it's not a major version upgrade, then
  --     don't include the pdb archive log size for apex
  --
  FOR i in 1..cmp_info.count LOOP
    IF cmp_info(i).processed THEN

      check_stmt := check_stmt_0 || '''' || cmp_info(i).cid || '''';

      BEGIN
        EXECUTE IMMEDIATE
           check_stmt
           INTO rowcount;
      EXCEPTION
        WHEN OTHERS THEN
          dbms_output.put_line('ORA' || SQLCODE ||
                               ': Error in FIND_ALL_PDB_ARCHIVE_SIZE:');
          dbms_output.put_line(SQLERRM);
          rowcount := 0;
      END;

      IF debug_archive_fra = TRUE THEN
        dbms_output.put_line('ARCHIVE/FRA: ' || cmp_info(i).cid || ' ' ||
                             '# of pdbs ' || rowcount);
      END IF;
 
      IF (cmp_info(i).cid <> 'APEX') OR
         (cmp_info(i).cid = 'APEX' and is_apex_will_be_upgraded = TRUE) 
      THEN
        min_pdb_archivelog_gen :=
          min_pdb_archivelog_gen +
              ((cmp_info(i).pdb_archivelog_kb * c_kb) * rowcount);

        IF debug_archive_fra = TRUE THEN
          dbms_output.put_line('ARCHIVE/FRA: ' || cmp_info(i).cid ||
                               ' pdb archive size ' ||
                               cmp_info(i).pdb_archivelog_kb);
          dbms_output.put_line('ARCHIVE/FRA: min_pdb_archivelog_gen ' ||
                               min_pdb_archivelog_gen);
        END IF;
      END IF;
    END IF;
  END LOOP;

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: end of find_all_pdb_archive_size');
  END IF;

  -- return estimated minimum of archivelog size generated for all pdbs for now
  RETURN min_pdb_archivelog_gen;

END find_all_pdb_archive_size;


-- *****************************************************************
--     find_archive_dest_info Section
--
--
-- *****************************************************************

PROCEDURE find_archive_dest_info
IS
  dest_name          VARCHAR2(256) := '';  -- e.g. LOG_ARCHIVE_DEST_1
  destination        VARCHAR2(256) := '';  -- path to archived logs
  continue_check     BOOLEAN := TRUE;  -- continue checking if alert is needed 
  check_stmt         VARCHAR2(1000);   -- check if alert is needed
  min_archivelog_gen     NUMBER := 0;  -- min non-cdb/root archive bytes
  min_allpdb_archive_gen NUMBER := 0;  -- min archivelog bytes for all pdbs

BEGIN

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: begin of find_archive_dest_info');
  END IF;

  --
  -- step 0: initialize archivedest_info record
  --
  archivedest_info.dest_name := '';
  archivedest_info.destination := '';
  archivedest_info.status := 'INACTIVE';
  archivedest_info.min_archive_gen := 0;


  --
  -- step 1A:
  -- if db is a pdb, then no need to continue as this is a global check
  --
  IF (db_is_cdb = TRUE AND db_is_root = FALSE) THEN
    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: exiting because in pdb');
    END IF;
    RETURN;
  END IF;


  --
  -- step 1B:
  -- if db is not in archivelog mode. then no need to contiue
  --
  IF db_log_mode <> 'ARCHIVELOG' THEN
    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: exiting because db not in ' ||
                           'archivelog mode');
    END IF;
    RETURN;
  END IF;

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: find_archive_dest_info: db_n_pdbs '
                         || db_n_pdbs);
  END IF;


  --
  -- step 2:
  -- calculate the minimum amount of archive logs for the upgrade
  -- that can be generated if ARCHIVING is on
  min_archivelog_gen := 0;   -- in bytes
  FOR i in 1..cmp_info.count LOOP
    IF cmp_info(i).processed THEN
      min_archivelog_gen := min_archivelog_gen
                            + (cmp_info(i).archivelog_kbytes * c_kb);
      IF debug_archive_fra = TRUE THEN
        dbms_output.put_line('ARCHIVE/FRA: ' || cmp_info(i).cid ||
                             ' archive size ' || cmp_info(i).archivelog_kbytes);
      END IF; 
    END IF;
  END LOOP;

  -- if there's at least 1 pdb, then return pdb archivelog minimum size for
  -- all pdbs.  the size returned is in bytes.
  IF db_n_pdbs > 1 THEN
    min_allpdb_archive_gen := find_all_pdb_archive_size;
  END IF; 

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: min_archivelog_gen without pdbs ' ||
                         min_archivelog_gen);
    dbms_output.put_line('ARCHIVE/FRA: min_allpdb_archive_gen for all pdbs ' ||
                         min_allpdb_archive_gen);
    dbms_output.put_line('ARCHIVE/FRA: db_n_pdbs ' || db_n_pdbs);
  END IF;

  -- total estimated minimum amount of archive log size generated in upgrade.
  -- min_archivelog_gen is in bytes for non-cdb and cdb.
  -- for now, caculate as if the entire cdb is upgrading.
  min_archivelog_gen := min_archivelog_gen + min_allpdb_archive_gen;

  archivedest_info.min_archive_gen := min_archivelog_gen;

  -- min_archivelog_gen is in bytes; pMinArchiveLogGen is in KBytes
  pMinArchiveLogGen := min_archivelog_gen / c_kb;


  --
  -- step 3:
  -- Determine whether archive destination outside of FRA is set.
  -- note: we only want 1 log_archive_dest_N to be returned
  -- note: we only care about TARGET='PRIMARY' because we want to exclude
  --       those cases when there is a standby in the configuration.
  --
  check_stmt :=
    'SELECT dest_name, destination, status ' || 
    'FROM sys.v$archive_dest ' ||
    'WHERE ' ||
      'upper(status) <> ''INACTIVE'' ' ||
      'AND destination IS NOT NULL ' ||
      'AND destination <> ''USE_DB_RECOVERY_FILE_DEST'' ' ||
      'AND destination NOT IN ' ||
      '  (select value from v$parameter ' ||
      '     where name = ''db_recovery_file_dest'' AND value IS NOT NULL) ' ||
      'AND target=''PRIMARY'' ' ||
      'AND rownum = 1';

  BEGIN
    EXECUTE IMMEDIATE
       check_stmt
       INTO archivedest_info.dest_name,
            archivedest_info.destination,
            archivedest_info.status;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      continue_check := FALSE;
    WHEN OTHERS THEN
      continue_check := FALSE;
      dbms_output.put_line('ORA' || SQLCODE ||
                           ': Error in MIN_ARCH_DEST_SIZE_STEP_3:');
      dbms_output.put_line(SQLERRM);
  END; 

  IF (continue_check = FALSE) THEN
    -- no need to go further, as archive destination(s) outside of
    -- recovery area is not used
    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: exiting because archived logs ' ||
                           'are not going to a destination outside of fra');
    END IF;
    RETURN;
  END IF;

  -- if we're here, then there is at least one LOG_ARCHIVE_DEST_<N> specified
  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: name ' || archivedest_info.dest_name);
    dbms_output.put_line('ARCHIVE/FRA: dest ' || archivedest_info.destination);
    dbms_output.put_line('ARCHIVE/FRA: status ' || archivedest_info.status);
  END IF;
    

  --
  -- step 4: return.
  -- If we're here, then note:
  -- archive logs destination is outside of FRA and
  -- the size cap is NOT controlled by DB_RECOVERY_FILE_DEST_SIZE.
  --

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: pMinArchiveLogGen ' ||
                         pMinArchiveLogGen);
    dbms_output.put_line('ARCHIVE/FRA: end of find_archive_dest_info');
  END IF;

  RETURN;

END find_archive_dest_info;

-- *****************************************************************
--     find_recovery_area_info
--
-- Determine minimum free space needed for when:
--  a) Archivelog is on
--  b) Flashback Database is on
--
-- *****************************************************************

PROCEDURE find_recovery_area_info
IS
  continue_check     BOOLEAN := TRUE;  -- continue checking if alert is needed 
  row_count          NUMBER  := 0;     -- row found if row count >= 1

  space_limit        NUMBER := 0;     -- bytes in db_recovery_file_dest_size
  space_used         NUMBER := 0;     -- bytes used from space_limit 
  space_reclaimable  NUMBER := 0;     -- bytes reclaimable from space_used
  space_avail        NUMBER := 0;     -- bytes avail from space_limit (bytes)
  fra_files          NUMBER := 0;     -- # of files in recovery area
  new_spacelimit     NUMBER := 0;     -- new minimum space_limit in bytes

  check_stmt  VARCHAR2(1000);                        -- check if alert is needed
  fra_dest    V$RECOVERY_FILE_DEST.NAME%TYPE := '';  -- dba_recovery_file_dest

  min_archivelog_gen     NUMBER := 0;  -- min archivelog bytes to be generated
  min_flashback_gen      NUMBER := 0;  -- min flashback bytes to be generated
  min_freespace_reqd     NUMBER := 0;  -- min free space needed for fra to grow
                                       -- sum of archivelog + flashbacklog bytes
  additional_size        NUMBER := 0;  -- size to be added to
                                       -- db_recovery_file_dest_size

BEGIN

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: begin of find_recovery_area');
  END IF;


  --
  -- step 0: initialize fra_info record
  --
  fra_info.name               := '';  -- destination name/path
  fra_info.limit              := 0;   -- db_recovery_file_dest_size (bytes)
  fra_info.used               := 0;   -- Used (bytes)
  fra_info.dsize              := 0;   -- db_recovery_file_dest_size (bytes)
  fra_info.reclaimable        := 0;   -- bytes reclaimable
  fra_info.files              := 0;   -- number of files
  fra_info.avail              := 0;   -- bytes available in FRA
  fra_info.min_archive_gen    := 0;   -- minimum archive logs (bytes) estimated
  fra_info.min_flashback_gen  := 0;   -- rough minimum flashback logs (bytes)
  fra_info.min_fra_size       := 0;   -- new db_recovery_file_dest_size to set
  fra_info.min_freespace_reqd := 0;   -- min free space needed for logs
  fra_info.additional_size    := 0;   -- additional size + limit = min_fra_size


  --
  -- step 1A:
  -- if db is a pdb, then no need to continue as this is a global check
  --
  IF (db_is_cdb = TRUE AND db_is_root = FALSE) THEN
    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: exiting because in pdb');
    END IF;
    RETURN;
  END IF;


  --
  -- step 1B:
  -- no need to continue if FRA is not enabled
  -- i.e. db_recovery_file_dest nor db_recovery_file_dest_size are not set
  --
  IF (db_fra_set = FALSE) THEN
    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: exiting because fra not set');
    END IF;
    RETURN;
  END IF;


  --
  -- step 2:
  -- db is not in archivelog mode.
  -- and if archivelog is not on, then flashback cannot be on.
  -- then no need to continue with the checks as no archive nor flashback
  -- logs will be generated into FRA 
  --
  IF db_log_mode <> 'ARCHIVELOG' THEN
    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: exit because archivelog mode not set');
    END IF;
    RETURN; 
  END IF;


  --
  -- step 3:
  -- find info about recovery area
  -- is recovery area set?
  --
  check_stmt :=
  'SELECT r.name, r.space_limit, r.space_used, r.space_reclaimable, ' ||
  '  r.number_of_files ' ||
  'FROM sys.v$recovery_file_dest r, sys.v$parameter p '||
  'WHERE ' ||
    'r.name = p.value ' ||
    '  AND p.name = ''db_recovery_file_dest'' ' ;

  BEGIN
    EXECUTE IMMEDIATE
       check_stmt
       INTO fra_dest, space_limit, space_used, space_reclaimable, fra_files;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      continue_check := FALSE;
      -- something wrong if FRA is enabled but no data returned... 
      dbms_output.put_line('ORA' || SQLCODE ||
                           ': Error in FIND_RECOVERY_AREA step 3a:');
      dbms_output.put_line(SQLERRM);
    WHEN OTHERS THEN
      continue_check := FALSE;
      dbms_output.put_line('ORA' || SQLCODE ||
                           ': Error in FIND_RECOVERY_AREA step 3b:');
      dbms_output.put_line(SQLERRM);
  END; 

  IF (continue_check = FALSE) THEN
    -- no need to go further, as failure to find recovery area info.
    -- error raised above.
    RETURN;
  END IF;


  --
  -- step 4:
  -- there can be 1 or more destinations for archive logs.
  -- we just want to know if one of the archive log destination(s) is FRA?
  -- note: we only care about TARGET='PRIMARY' because we want to exclude
  --       those cases when there is a standby in the configuration.
  -- 
  check_stmt :=
    'SELECT count(*) ' || 
    'FROM sys.v$archive_dest ' ||
    'WHERE ' ||
      '(destination = ''USE_DB_RECOVERY_FILE_DEST'' ' ||
      '   OR destination = ' ||
      '      (select value from v$parameter ' ||
      '       where name = ''db_recovery_file_dest'' ' ||
      '         AND value IS NOT NULL)) '||
      'AND target=''PRIMARY'' ' ||
      'AND upper(status) <> ''INACTIVE'' ';

  BEGIN
    EXECUTE IMMEDIATE
       check_stmt
       INTO row_count;
  EXCEPTION
    WHEN OTHERS THEN
      continue_check := FALSE;
      dbms_output.put_line('ORA' || SQLCODE ||
                           ': Error in FIND_RECOVERY_AREA step 4:');
      dbms_output.put_line(SQLERRM);
  END; 
 

  --
  -- step 5:
  -- if one of the archive log destination(s) is FRA, then determine
  -- how much free space is required in FRA for archive logs: 
  is_archivelog_in_fra := FALSE;  -- initialize
  IF row_count >= 1 THEN
    is_archivelog_in_fra := TRUE;  -- set global variable

    -- min_archive_gen is in bytes
    -- min_freespace_reqd is in bytes
    -- pMinArchiveLogGen is in KBytes
    min_archivelog_gen := pMinArchiveLogGen * c_kb;
    min_freespace_reqd := min_archivelog_gen;
  ELSE
    min_freespace_reqd := 0;
  END IF;

  IF debug_archive_fra = TRUE THEN
    IF is_archivelog_in_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: is_archivelog_in_fra is TRUE');
    ELSE
      dbms_output.put_line('ARCHIVE/FRA: is_archivelog_in_fra is FALSE');
    END IF;
  END IF;

  --
  -- step 6:
  -- calculate the minimum amount of flashback logs for the upgrade
  -- that can be generated if FLASHBACK is on
  --
  IF db_flashback_on = TRUE THEN
    FOR i in 1..cmp_info.count LOOP
      -- this is for non-cdb OR ROOT
      IF cmp_info(i).processed THEN
        -- min_flashback_gen is in bytes
        min_flashback_gen := min_flashback_gen
                                + (cmp_info(i).flashbacklog_kbytes * c_kb);
        IF debug_archive_fra = TRUE THEN
          dbms_output.put_line('ARCHIVE/FRA: ' || cmp_info(i).cid ||
                               ' flashback size ' ||
                               cmp_info(i).flashbacklog_kbytes);
        END IF; 
      END IF;
    END LOOP;

    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: min_flashback_gen without pdbs ' ||
                           min_flashback_gen);
    END IF;

    -- include an estimate for flasbhback logs generated for SEED and PDBs
    -- min_flashback_gen is in bytes
    min_flashback_gen := min_flashback_gen +
                            ((C_MIN_FLASHBACK_KB_PER_PDB * c_kb) * db_n_pdbs);
 
    -- min_flashback_gen is in bytes; pMinFlashbackLogGen is in KBytes
    pMinFlashbackLogGen  := min_flashback_gen / c_kb;

    IF debug_archive_fra = TRUE THEN
      dbms_output.put_line('ARCHIVE/FRA: min_freespace_reqd with archive ' ||
                           'in fra is ' || min_freespace_reqd);
      dbms_output.put_line('ARCHIVE/FRA: min_flashback_gen with pdbs ' ||
                           min_flashback_gen);
      dbms_output.put_line('ARCHIVE/FRA: final pMinFlashbackLogGen ' ||
                           pMinFlashbackLogGen);
    END IF;
  END IF;


  --
  -- step 7:
  -- mathematical calculations
  --

  -- from step 5, add up min freespace needed for archive logs (if any) +
  -- min freespace needed for flashback logs in fra
  min_freespace_reqd := min_freespace_reqd + min_flashback_gen;

  -- note: space_avail can be negative # if space_used > space_limit
  space_avail := space_limit - space_used;

  IF space_avail >= min_freespace_reqd THEN
    new_spacelimit  := min_freespace_reqd + space_used;
    additional_size := 0;
  ELSE  -- space_avail < min_freespace_reqd
    new_spacelimit  := space_limit + (min_freespace_reqd - space_avail);
    additional_size := new_spacelimit - space_limit;
  END IF;

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: space_limit ' || space_limit);
    dbms_output.put_line('ARCHIVE/FRA: space_used '  || space_used);
    dbms_output.put_line('ARCHIVE/FRA: space_avail ' || space_avail);
    dbms_output.put_line('ARCHIVE/FRA: min_freespace_reqd ' ||
                         min_freespace_reqd);
    dbms_output.put_line('ARCHIVE/FRA: new_spacelimit '  || new_spacelimit);
    dbms_output.put_line('ARCHIVE/FRA: additional_size ' || additional_size);
  END IF;


  --
  -- step 8: assign values back to fra_info
  --
  fra_info.name               := fra_dest;
  fra_info.limit              := space_limit;
  fra_info.used               := space_used;
  fra_info.dsize              := space_limit;
  fra_info.reclaimable        := space_reclaimable;
  fra_info.files              := fra_files;
  IF space_avail >= 0 THEN  -- do not display a negative value for avail space
    fra_info.avail            := space_avail;
  ELSE
    fra_info.avail            := 0;
  END IF;
  fra_info.min_archive_gen    := min_archivelog_gen;  -- generated in fra
  fra_info.min_flashback_gen  := min_flashback_gen;   -- generated in fra
  fra_info.min_fra_size       := new_spacelimit;
  fra_info.min_freespace_reqd := min_freespace_reqd;
  fra_info.additional_size    := additional_size;

  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: end of find_recovery_area');
  END IF;

  RETURN; 

END find_recovery_area_info;

--
-- ***********************************************************************
--                         Actual CHECK FUNCTIONs
-- ***********************************************************************
--


FUNCTION run_preupgrade(output_filename IN VARCHAR2 DEFAULT null,
                        xml IN BOOLEAN DEFAULT false) RETURN BOOLEAN
IS
    result CLOB;
    check_count NUMBER;
    output_file UTL_FILE.FILE_TYPE;
    result_length NUMBER;
    crlf_length NUMBER;
    this_line clob;
    this_line_start_index NUMBER := 1;
    this_line_end_index NUMBER;
    split_line VARCHAR2(32766);
    line_number NUMBER;
    output_is_file BOOLEAN;
    preupgrade_result BOOLEAN := false;
    result_clob CLOB;
    clob_length INTEGER;
    v_buffer varchar2(32000);
    chunk_size BINARY_INTEGER := 3000;
    clob_position INTEGER := 1;	
    this_line_len integer;
    text_output_mode BOOLEAN;

BEGIN 
    BEGIN
	text_output_mode := not XML;
        output_is_file := (output_filename IS NOT NULL);

        -- open the file now, its always annoying to wait for a
        -- potentially slow routine (run_all_checks) only to
        -- find out we couldn't open the output file.

        IF (output_is_file) THEN
            output_file := utl_file.fopen('PREUPGRADE_DIR',output_filename, 'w', 32767);
        END IF;

        check_count := run_all_checks(result);

        IF (text_output_mode) THEN
            result := xml_to_text(result);
        END IF;

        result := result || crlf;	-- make it end with a crlf so the loop below handles all output.
        result_length := length(result);
        crlf_length := length(crlf);
	result_clob := result;
        this_line_end_index := instr(result_clob, crlf, this_line_start_index);
        WHILE (this_line_end_index <> 0) LOOP
            this_line := substr(result_clob, this_line_start_index, 
                                                   this_line_end_index-this_line_start_index);
	    this_line_len := length(this_line);

            IF text_output_mode THEN
                --
                --  this_line may be too long to emit directly to the terminal.
                --  so chop it up.
                --
                this_line := fit_to_terminal(this_line, C_TERMINAL_WIDTH);
            END IF;

            IF (output_is_file) THEN
	         to_file(output_file, this_line);
            ELSE
                dbms_output.put_line(this_line);
	    END IF;

            this_line_start_index := this_line_end_index + crlf_length;
            this_line_end_index := instr(result_clob, crlf, this_line_start_index);
        END LOOP;

	IF (output_is_file) THEN
	    utl_file.fflush(output_file);
 	    utl_file.fclose(output_file);
	END IF;

        preupgrade_result := true;

    EXCEPTION
        WHEN invalidFileOperation THEN
            dbms_output.put_line('ERROR - cannot open output filename ' || output_filename || ' in preupgrade_dir');
            preupgrade_result := false;
        WHEN OTHERS THEN
            --
            --    This is essentially the preupgrade's catch-all handler.
            --
            dbms_output.put_line(dbms_utility.format_error_backtrace);
            internal_error(SQLERRM);
            preupgrade_result := false;
    END;

    return preupgrade_result;

END run_preupgrade;

--
--    This function runs all registered checks and generates FIXUP scripts
--    as needed.
--
FUNCTION run_all_checks(result_xml OUT CLOB) RETURN NUMBER
IS
    successful_checks NUMBER := 0;
    failed_checks_pre NUMBER := 0;         -- number of failed checks whose check_type=PRE
    failed_checks_validation NUMBER := 0;  -- number of failed checks whose check_type=VALIDATION
    failed_checks_post NUMBER := 0;        -- number of failed checks whose check_type=POST
    check_result BOOLEAN;
    check_result_xml CLOB;
    check_index NUMBER;
    this_check check_record_t;
    preupgradecheck preupgradecheck_t;
    original_message VARCHAR2(4000);
    final_suffix VARCHAR2(4000);

    fixup_script_pre  utl_file.file_type;
    fixup_script_post utl_file.file_type;
    fixup_script      utl_file.file_type;   -- will be equal to either fixup_script_pre or fixup_script_post

BEGIN
    result_xml := '';

    result_xml := result_xml || gen_rdbmsup_xml
                             || gen_database_xml
                             || gen_components_xml
                             || gen_systemresource_xml
                             || gen_initparams_xml
                             || '<PreUpgradeChecks>' || crlf;

    FOR check_index IN 1..check_table.count LOOP
        this_check := check_table(check_index);

        IF debug THEN
            dbms_output.put_line('in run_all_checks, about to run_check on ' || this_check.name);
        END IF;

        --
        --    Run individual check
        --
        check_result := run_check(this_check.name, check_result_xml);

        IF debug THEN
            dbms_output.put_line('run_check(' || this_check.name || ') returned:' || boolean_string(check_result));
            dbms_output.put_line(check_result_xml);
        END IF;

        result_xml := result_xml || check_result_xml;

        IF check_result THEN
            successful_checks := successful_checks + 1;
        ELSE

            --
            --    If the CHECK failed, generate the FIXUP code.
            --
            IF (this_check.fixup_stage = 'PRE') THEN
                failed_checks_pre := failed_checks_pre + 1;
                IF (failed_checks_pre + failed_checks_validation = 1) THEN
                    fixup_script_pre := open_and_start_emitting_fixup(this_check.fixup_stage);
                END IF;
                fixup_script := fixup_script_pre;
            ELSIF (this_check.fixup_stage = 'POST') THEN
                failed_checks_post := failed_checks_post + 1;
                IF (failed_checks_post = 1) THEN
                    fixup_script_post := open_and_start_emitting_fixup(this_check.fixup_stage);
                END IF;
                fixup_script := fixup_script_post;
            ELSIF (this_check.fixup_stage = 'VALIDATION') THEN
                -- these "validation" phase fixups are like PRE's except they're "JUST BEFORE" upgrade.
                failed_checks_validation := failed_checks_validation + 1;
                IF (failed_checks_pre + failed_checks_validation = 1) THEN
                    fixup_script_pre := open_and_start_emitting_fixup('PRE');
                END IF;
                fixup_script := fixup_script_pre;
            ELSE
                internal_error('unknown fixup_stage value, ' || this_check.fixup_stage || '.');
            END IF;

            preupgradecheck := parse_preupgradecheck_xml(check_result_xml, 1, length(check_result_xml));
            IF (preupgradecheck.id IS NULL) THEN
                original_message := 'Unknown message';
            ELSE
                original_message := preupgradecheck_t_to_text(preupgradecheck);
            END IF;
            original_message := smart_pad(original_message, 200, '    --  ');

            --
            --    Emit the code near the call to the CHECK-specific fixup routine.
            --    this way the user knows/remembers the specific context of the original failure.
            --
            utl_file.put_line(fixup_script, ' ');
            utl_file.put_line(fixup_script, '    --');
            utl_file.put_line(fixup_script, '    --    CHECK/FIXUP name: ' || this_check.name);
            utl_file.put_line(fixup_script, '    --');
            utl_file.put_line(fixup_script, '    --    The call to run_fixup below will test whether');
            utl_file.put_line(fixup_script, '    --    the following issue originally identified by');
            utl_file.put_line(fixup_script, '    --    the preupgrade tool is still present');
            utl_file.put_line(fixup_script, '    --    and if so, it will attempt to perform the action');
            utl_file.put_line(fixup_script, '    --    necessary to resolve it.');
            utl_file.put_line(fixup_script, '    --');
            utl_file.put_line(fixup_script, '    --    ORIGINAL PREUPGRADE ISSUE:');
            utl_file.put_line(fixup_script, original_message);
            utl_file.put_line(fixup_script, '    --');
            utl_file.put_line(fixup_script, '    fixup_result := dbms_preup.run_fixup(''' || this_check.name || ''');' );

        END IF;
    END LOOP;

    --
    --    Close the FIXUP scripts if we wrote them.
    --
    IF (failed_checks_pre > 0) or (failed_checks_validation > 0) THEN
        finish_emitting_fixup(fixup_script_pre, 'PRE');
    END IF;
    IF (failed_checks_post > 0) THEN
        finish_emitting_fixup(fixup_script_post, 'POST');
    END IF;

    final_suffix := '</PreUpgradeChecks>' || crlf || '</RDBMSUP>' || crlf;
    IF NOT db_is_cdb THEN
        final_suffix := final_suffix || '</Upgrade>' || crlf;
    END IF;

    result_xml := result_xml || final_suffix;

    return successful_checks + failed_checks_pre + failed_checks_validation + failed_checks_post;
END run_all_checks;

FUNCTION run_check(check_name IN VARCHAR2, result_xml OUT VARCHAR2) RETURN BOOLEAN
IS
    this_check_record check_record_t;
    check_stmt VARCHAR2(300);
    check_result NUMBER;
    min_version_ok BOOLEAN;
    max_version_ok BOOLEAN;
BEGIN
    IF debug THEN
        dbms_output.put_line('in run_check for check name: ' || check_name);
    END IF;

    this_check_record := get_check_record_by_name(check_name);
    IF (this_check_record.name IS NULL) THEN
        internal_error('In run_check, Pre-Upgrade Package Requested Check "' || check_name || '" does not exist');
    END IF;
    --
    --    Decide whether this CHECK is applicable to this db_version
    --
    min_version_ok := (this_check_record.min_version = 'NONE') OR
                      (dbms_registry_extended.compare_versions(db_version_4_dots,
                                        this_check_record.min_version,
                                        dbms_registry_extended.occurs(this_check_record.min_version, '.')) >= 0 );

    max_version_ok := (upper(this_check_record.max_version) = 'NONE') OR
                      (dbms_registry_extended.compare_versions(db_version_4_dots,
                                        this_check_record.max_version,
                                        dbms_registry_extended.occurs(this_check_record.max_version, '.')) <= 0 );

    IF (min_version_ok AND max_version_ok) THEN
        --
        --    Call the CHECK
        --
        BEGIN
            check_stmt := 'BEGIN ' || ':1 := dbms_preup.' ||
                              dbms_assert.simple_sql_name(this_check_record.name) || '_check (:2); ' ||
                          'END;';

            EXECUTE IMMEDIATE check_stmt
                USING OUT check_result, IN OUT result_xml;
        EXCEPTION
            WHEN stringNotSimpleSQLName THEN
                --
                --    The checkname is invalid somehow.  Get out.
                --
                internal_error('preupgrade check "' || check_name || '" not valid.');
            WHEN e_undefinedFunction THEN
                internal_error('check "' || check_name || '" not implemented.');
            WHEN OTHERS THEN
                --
                --    This could happen if the CHECK itself threw an exception.
                --
                dbms_output.put_line('check "' || check_name ||
                                     '" raised the following exception and did not complete. ' || crlf ||
                                     sqlerrm);
                dbms_output.put_line(dbms_utility.format_error_backtrace);
                dbms_output.put_line('preupgrade will attempt to continue from that error');
                result_xml := '';
                RETURN false;
        END;

        IF debug THEN
            dbms_output.put_line('Check ' || check_name || ' was called.  Returning ' ||
                boolean_string(check_result = c_success) );
        END IF;

    ELSE
        check_result := c_success;  -- the check does not appply to this version, so it essentially "passes".

        IF debug THEN
            dbms_output.put_line('Not running check ' || this_check_record.name ||
                ' because it does not apply to this database version.');
        END IF;
    END IF;

    RETURN (check_result = c_success);

END run_check;


FUNCTION oracle_reserved_users_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
BEGIN
    result_txt := '';

    --
    --    The version numbers in the second parameter to get_reserved_user_xml()
    --    should have 4 dots in them.
    --
    result_txt := result_txt || get_reserved_user_xml('ORACLE_OCM',         '10.2.0.4.0');
    result_txt := result_txt || get_reserved_user_xml('APPQOSSYS',          '11.2.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('AUDSYS',             '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('AUDIT_ADMIN',        '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('AUDIT_VIEWER',       '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('SYSBACKUP',          '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('SYSDG',              '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('SYSKM',              '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('CAPTURE_ADMIN',      '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('GSMCATUSER',         '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('GSMUSER',            '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('GSMADMIN_INTERNAL',  '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('GSMUSER_ROLE',       '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('GSMPOOLADMIN_ROLE',  '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('GSMADMIN_ROLE',      '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('GDS_CATALOG_SELECT', '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('PROVISIONER',        '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('XS_RESOURCE',        '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('XS_SESSION_ADMIN',   '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('XS_NAMESPACE_ADMIN', '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('XS_CACHE_ADMIN',     '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('EM_EXPRESS_BASIC',   '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('EM_EXPRESS_ALL',     '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('DV_AUDIT_CLEANUP',   '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('DV_DATAPUMP_NETWORK_LINK', '12.1.0.1.0');
    result_txt := result_txt || get_reserved_user_xml('SYSRAC',             '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('SYS$UMF',            '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('SYSUMF_ROLE',        '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('DBSFWUSER',          '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('DBSFWUSER_ROLE',     '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('REMOTE_SCHEDULER_AGENT','12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('GGSYS',              '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('GGSYS_ROLE',         '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('DV_POLICY_OWNER',    '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('XS_CONNECT',         '12.2.0.0.0');
    result_txt := result_txt || get_reserved_user_xml('APPLICATION_TRACE_VIEWER', '12.2.0.0.0');

    
    IF (result_txt IS NULL) THEN
        RETURN c_success;
    ELSE
        RETURN c_failure;
    END IF;
END oracle_reserved_users_check;


FUNCTION supported_version_check(result_txt OUT VARCHAR2) RETURN NUMBER
IS
BEGIN
    IF debug THEN
        dbms_output.put_line('in supported_version_check');
    END IF;

    IF (instr(',&C_UPGRADABLE_VERSIONS,',
              ',' || db_version_3_dots || ',') = 0) THEN
        IF debug THEN
            dbms_output.put_line('in supported_version_check, version not supported.');
        END IF;

        --
        --    The database version is not supported for upgrade.
        --
        result_txt := get_failed_check_xml('supported_version',
                          new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS,
                                   '&C_UPGRADABLE_VERSIONS',
                                   db_version_4_dots),
                null, null);
        IF debug THEN
            dbms_output.put_line('in supported_version_check, version not supported. result_txt=' || result_txt);
        END IF;

        RETURN c_failure;
    ELSE
        result_txt := '';
        RETURN c_success;
    END IF;
END supported_version_check;



FUNCTION compatible_parameter_check     (result_txt OUT VARCHAR2) RETURN NUMBER
IS
    status NUMBER;
BEGIN
    --
    --    If we have the correct min compat and not debug and not XML
    --    return success.
    --
    IF (dbms_registry_extended.compare_versions(db_compatible,
                         '&C_MINIMUM_COMPATIBLE',
                         dbms_registry_extended.occurs('&C_MINIMUM_COMPATIBLE','.') ) >= 0) THEN
        RETURN c_success;
    END IF;

    result_txt := get_failed_check_xml('compatible_parameter',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS,
                          '&C_MINIMUM_COMPATIBLE',
                          db_compatible),
                      null, null);
    RETURN c_failure;
END compatible_parameter_check;


FUNCTION ols_sys_move_check             (result_txt OUT VARCHAR2) RETURN NUMBER
IS
    preaud_cnt       INTEGER := 0;
    status           NUMBER  := -1;
    condition_exists BOOLEAN := FALSE;
BEGIN
    BEGIN
        -- Check if OLS is installed in previous version
        EXECUTE IMMEDIATE 'SELECT status FROM sys.registry$ WHERE cid=''OLS''
                           AND namespace=''SERVER'''
             INTO status;
        EXCEPTION WHEN OTHERS THEN NULL;
    END;

    --
    --    bug 16317592: check if SYS.aud$ already exists. may be upgrade
    --    script was run before. If SYS.aud$ exists, don't do anything
    --
    SELECT count(*) INTO preaud_cnt FROM dba_tables
           WHERE table_name = 'AUD$' AND owner = 'SYS';

    IF ((status != -1) AND (preaud_cnt != 1)) THEN
        BEGIN
            --
            -- This check means the ols script has not been executed
            --
            EXECUTE IMMEDIATE 'SELECT count(*) FROM dba_tables where OWNER=''SYS'' AND table_name=''PREUPG_AUD$'''
              into preaud_cnt;
            IF preaud_cnt = 0 THEN
              condition_exists := TRUE;
            END IF;
        END;
    END IF;

    IF (NOT condition_exists) THEN
        RETURN c_success;
    END IF;

    result_txt := get_failed_check_xml('ols_sys_move',
                      new string_array_t(db_version_4_dots,
                          C_ORACLE_HIGH_VERSION_4_DOTS,
                          to_char(preaud_cnt)),
                      null, null);
    RETURN c_failure;

END ols_sys_move_check;


FUNCTION awr_dbids_present_check        (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  role_exists NUMBER := 1;
  t_null      CHAR(1);
  status      NUMBER;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE
     'SELECT distinct NULL FROM sys.wrm$_wr_control WHERE dbid != (SELECT dbid FROM v$database)'
      INTO t_null;
    EXCEPTION
      WHEN NO_DATA_FOUND then role_exists := 0;
  END;

  IF (role_exists = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('awr_dbids_present',
                      new string_array_t(),
                      null, null);
    RETURN c_failure;	
  END IF;
END awr_dbids_present_check;


FUNCTION pa_profile_check               (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  c             NUMBER;
  d             NUMBER;
  v_tab         DBMS_SQL.VARCHAR2_TABLE;
  enabled_count NUMBER := 0;
  tab_name      VARCHAR2(130);
  v_count       NUMBER := 0;
  row_count     NUMBER := 0;
  issue_found   BOOLEAN := FALSE;
  pa_view       VARCHAR2(128) := 'SYS.DBA_PRIV_CAPTURES';
BEGIN
  -- return success if view DBA_PRIV_CAPTURES does not exist
  SELECT COUNT(*) INTO v_count 
    FROM DBA_OBJECTS 
    WHERE OWNER = 'SYS' AND OBJECT_NAME = 'DBA_PRIV_CAPTURES' AND OBJECT_TYPE = 'VIEW';

  IF v_count = 0 THEN
    RETURN c_success;
  END IF;

  -- return success if view DBA_SECUREFILE_LOG_TABLES does not exist
  SELECT COUNT(*) INTO v_count 
    FROM DBA_OBJECTS 
    WHERE OWNER = 'SYS' AND OBJECT_NAME = 'DBA_SECUREFILE_LOG_TABLES' AND OBJECT_TYPE = 'VIEW';
  IF v_count = 0 THEN
    RETURN c_success;
  END IF;

  BEGIN
    EXECUTE IMMEDIATE 'SELECT COUNT(name) FROM ' || pa_view || ' WHERE enabled=''Y''' INTO enabled_count;
  EXCEPTION
      WHEN OTHERS THEN NULL;
  END;

  c := DBMS_SQL.OPEN_CURSOR;
  DBMS_SQL.PARSE(c, 'SELECT table_name
                     FROM dba_securefile_log_tables
                     WHERE log_name LIKE ''ORA$PA_%'' OR log_name LIKE ''ORA$PRIV_CAPTURE_%''', 
                 DBMS_SQL.NATIVE);
  DBMS_SQL.DEFINE_ARRAY(c, 1, v_tab, 1, 1);

  /* execute SQL statement */
  d := DBMS_SQL.EXECUTE(c);

  /* retrieve column values to column table */
  LOOP
    EXIT WHEN DBMS_SQL.FETCH_ROWS(c) = 0;
    row_count := row_count + 1;
    DBMS_SQL.COLUMN_VALUE(c, 1, v_tab);
  END LOOP;

  DBMS_SQL.CLOSE_CURSOR(c);

  FOR i IN 1..row_count LOOP
    tab_name := DBMS_ASSERT.ENQUOTE_NAME(v_tab(i), FALSE);
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || tab_name INTO v_count;
    IF v_count > 0 THEN
      issue_found := TRUE;
      EXIT;
    END IF;
  END LOOP;

  IF (enabled_count > 0 OR issue_found) THEN
    result_txt := get_failed_check_xml('pa_profile',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS),
                      null, null);
    RETURN c_failure;
  ELSE
    RETURN c_success;
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    IF DBMS_SQL.IS_OPEN(c) THEN
      DBMS_SQL.CLOSE_CURSOR(c);
    END IF;
    RETURN c_failure;
END pa_profile_check;


FUNCTION em_present_check               (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null      CHAR(1);
  status      NUMBER;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE  'SELECT NULL FROM sys.registry$ WHERE cid=''EM''
      AND status NOT IN (99,8)'
    INTO  t_null;
      status := 1;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
      status := 0;
  END;

  IF (status = 0)
  THEN
    -- EM not here.
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('em_present',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS, db_version_4_dots),
                      null, null);
    RETURN c_failure;
  END IF;
END em_present_check;



FUNCTION files_need_recovery_check      (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null      CHAR(1);
  status      NUMBER;
  c_recover_sql_text CONSTANT VARCHAR2(250) :=
        'SELECT NULL FROM v$recover_file WHERE error <> ''OFFLINE NORMAL'' and rownum <=1';
  c_recover_sql_cdb  CONSTANT VARCHAR2(250) :=
        ' AND con_id = sys.dbms_preup.get_con_id()';
  stmttext    VARCHAR2(200) := c_recover_sql_text;
BEGIN
  --
  -- Cdb Database add con id check
  --
  IF db_is_cdb THEN
      stmttext := stmttext || c_recover_sql_cdb;
  END IF;

  BEGIN

    EXECUTE IMMEDIATE stmttext INTO t_null;
      status := 1;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN status := 0;
  END;

  IF (status = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('files_need_recovery',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS),
                      null, null);
    RETURN c_failure;
  END IF;
END files_need_recovery_check;


FUNCTION files_backup_mode_check        (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  roll_exists NUMBER := 1;
  t_null      CHAR(1);
  status      NUMBER;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE
     'SELECT NULL FROM v$backup  WHERE
           status = ''ACTIVE'' AND rownum <=1'
      INTO t_null;
    EXCEPTION
      WHEN NO_DATA_FOUND then roll_exists := 0;
  END;

  IF (roll_exists = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('files_backup_mode',
                      new string_array_t(),
                      null, null);
    RETURN c_failure;
  END IF;
END files_backup_mode_check;


FUNCTION two_pc_txn_exist_check         (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null      CHAR(1);
  status      NUMBER;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE 'SELECT NULL FROM sys.dba_2pc_pending WHERE rownum <=1'
    INTO t_null;
      status := 1;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN status := 0;
  END;

  IF (status = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('two_pc_txn_exist',
                      new string_array_t(),
                      null, null);
    RETURN c_failure;
  END IF;

END two_pc_txn_exist_check;


FUNCTION sync_standby_db_check          (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null                 CHAR(1);
  status                 NUMBER := 0;
  unsynch_standby_count  NUMBER := 0;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE 'SELECT NULL FROM v$parameter WHERE
       name LIKE ''log_archive_dest%'' AND upper(value) LIKE ''SERVICE%''
       AND rownum <=1'
    INTO t_null;

    EXECUTE IMMEDIATE 'SELECT NULL FROM v$database WHERE
       database_role=''PRIMARY'''
    INTO t_null;

    EXECUTE IMMEDIATE 'SELECT COUNT(*)
                         FROM V$ARCHIVE_DEST_STATUS DS, V$ARCHIVE_DEST D
                         WHERE DS.DEST_ID = D.DEST_ID
                               AND D.TARGET = ''STANDBY''
                               AND NOT (DS.STATUS = ''VALID'' AND DS.GAP_STATUS = ''NO GAP'')'
    INTO unsynch_standby_count;
    IF (unsynch_standby_count > 0) THEN
        status := 1;
    END IF;

  EXCEPTION
      WHEN NO_DATA_FOUND THEN status := 0;
  END;

  IF (status = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('sync_standby_db',
                      new string_array_t(),
                      null, null);
    RETURN c_failure;
   END IF;
END sync_standby_db_check;


FUNCTION ultrasearch_data_check         (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  status  NUMBER := 0;
  i_count INTEGER;
BEGIN
  --
  -- Once Ultra Search instance is created, wk$instance table is populated.
  -- The logic determines if Ultra Search has data or not by looking up
  -- wk$instance table. WKSYS.WK$INSTANCE table exists when Ultra Search is
  -- installed. If it's not installed, WKSYS.WK$INSTANCE doesn't exist and the
  -- pl/sql block raises exception.
  --
  BEGIN
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM wksys.wk$instance'
      INTO i_count;
    -- count will be 0 when there are no rows in wksys.wk$instance
    -- Otherwise there is at least one row in
    -- and an ultra search warning should be displayed
    IF (i_count != 0) THEN
       status := 1;
    END IF;
    EXCEPTION WHEN OTHERS THEN NULL;
  END;

  IF (status = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('ultrasearch_data',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS),
                      null, null);

    RETURN c_failure;
   END IF;
END ultrasearch_data_check;


FUNCTION remote_redo_check              (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  tmp_varchar1 VARCHAR2(100);
  t_count      INTEGER;
  status       NUMBER := 0;
BEGIN
  --
  -- Check to detect if REDO configuration is supported with beyond
  -- 11.2
  --
  --  For 11.2, REDO has changed its maximum number of remote redo transport
  --  destinations from 9 to 30, we need to see if 10 is being used, and what
  --  its default is, if its local, there is an error.
  --
  -- Condition 1) Archiving of log files is enabled
  --
  -- Condition 2) DB_RECOVERY_FILE_DEST is defined
  --
  -- Condition 3) No local destinations are defined
  --
  -- Condition 4) LOG_ARCHIVE_DEST_1 is in use, and is a remote destition
  --
  --
  -- Only continue if archive logging is on
  --

  BEGIN
    EXECUTE IMMEDIATE
      'SELECT LOG_MODE FROM v$database'
      INTO tmp_varchar1;
    EXCEPTION
       WHEN NO_DATA_FOUND THEN tmp_varchar1 := 'NOARCHIVELOG';
  END;

  IF tmp_varchar1 != 'ARCHIVELOG' THEN
    RETURN c_success;
  END IF;

  --
  -- Check for db_recovery_file_dest
  --
  tmp_varchar1 := NULL;
  BEGIN
    EXECUTE IMMEDIATE 'SELECT vp.value FROM v$parameter vp WHERE
               UPPER(vp.NAME) = ''DB_RECOVERY_FILE_DEST'''
    INTO tmp_varchar1;

    EXCEPTION
      WHEN NO_DATA_FOUND THEN NULL;
  END;

  IF tmp_varchar1 IS NOT NULL OR tmp_varchar1 != '' THEN
    --
    -- See if there are any local destinations defined
    -- Note the regexp_like
    --
    EXECUTE IMMEDIATE '
      SELECT count(*) FROM v$parameter v
        WHERE v.NAME  LIKE ''log_archive_dest_%'' AND
        REGEXP_LIKE(v.VALUE,''*[ ^]?location([ ])?=([ ])?*'')'
    INTO t_count;

    IF t_count > 0 THEN
      --
      -- Next is _1 in use, and remote
      --
      EXECUTE IMMEDIATE '
        SELECT count(*) FROM v$archive_dest ad
        WHERE ad.status=''VALID'' AND ad.dest_id=1 AND
                 ad.target=''STANDBY'''
      INTO t_count;

      IF t_count = 1 THEN
        --
        -- There is an issue to report.
        --
        status := 1;
      END IF;
    END IF; -- t_count = 1
  END IF;  -- having local dest values set

  IF (status = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('remote_redo',
                      new string_array_t(db_version_4_dots,C_ORACLE_HIGH_VERSION_4_DOTS),
                      null, null);

    RETURN c_failure;
   END IF;
END remote_redo_check;


FUNCTION sys_default_tablespace_check   (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_ts1       VARCHAR2(30);
  t_ts2       VARCHAR2(30);
  status      NUMBER;
BEGIN

  EXECUTE IMMEDIATE 'SELECT default_tablespace FROM sys.dba_users WHERE username = ''SYS'''
  INTO t_ts1;
  EXECUTE IMMEDIATE 'SELECT default_tablespace FROM sys.dba_users WHERE username = ''SYSTEM'''
  INTO t_ts2;

  IF (t_ts1 = 'SYSTEM') AND (t_ts2 = 'SYSTEM') THEN
    -- Everything is fine.
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('sys_default_tablespace',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS,db_version_4_dots,t_ts1,t_ts2),
                      null, null);

    RETURN c_failure;
  END IF;
END sys_default_tablespace_check;

FUNCTION sys_default_tablespace_fixup (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN number
IS
  t_result_txt VARCHAR2(1000);
  t_ts1        VARCHAR2(128);
  rval         BOOLEAN;
BEGIN
  --
  --  Check both SYS and SYSTEM and reset if needed
  --
  result_txt := '';
  pSqlcode := 1;
  EXECUTE IMMEDIATE 'SELECT default_tablespace FROM sys.dba_users WHERE username = ''SYS'''  
  INTO t_ts1;
  IF (t_ts1 != 'SYSTEM') THEN
    result_txt := 'Altering SYS schema default tablespace.  Result: ';
    rval := execute_sql_statement ('ALTER USER SYS DEFAULT TABLESPACE SYSTEM', t_result_txt, pSqlcode);
    result_txt := result_txt || TO_CHAR(pSqlcode);
  END IF;

  EXECUTE IMMEDIATE 'SELECT default_tablespace FROM sys.dba_users WHERE username = ''SYSTEM'''  
  INTO t_ts1;
  IF (t_ts1 != 'SYSTEM') THEN
    result_txt := result_txt || crlf || 'Altering SYSTEM schema default tablespace Result: ';
    rval := execute_sql_statement ('ALTER USER SYSTEM DEFAULT TABLESPACE SYSTEM', t_result_txt, pSqlcode);
    result_txt := result_txt || TO_CHAR(pSqlcode);
  END IF;
  --
  -- If both were executed, only the last status is returned.
  --
  if (rval = TRUE) then
     return c_success;
  else
     return c_failure;
  end if;

END sys_default_tablespace_fixup;

FUNCTION invalid_laf_check              (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  laf_format   VARCHAR2(4000);
  tmp_varchar1 VARCHAR2(512);
  t_null       CHAR(1);
  status       NUMBER := 0;
BEGIN

   --
   -- invalid log_archive_format check
   --
   -- for 9.x, RDBMS set a default value which did not include %r,
   -- which is required by 11.2.
   -- Grab the format string, and if its defaulted or not,
   -- Only report an error if its NOT defaulted (user set) and it is
   -- missing the %r.
   --
   BEGIN
     EXECUTE IMMEDIATE
        'SELECT value, isdefault FROM v$parameter WHERE name = ''log_archive_format'''
     INTO laf_format, tmp_varchar1;
   EXCEPTION WHEN OTHERS THEN NULL;
   END;

   IF (tmp_varchar1 = 'FALSE') AND
      (instr (LOWER(laf_format), '%r') = 0) THEN
     --
     -- no %[r|R] and we are not defaulted by the system - we have to report something...
     --
     status := 1;
   END IF;

  IF (status = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('invalid_laf',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS,laf_format),
                      null, null);
 
    RETURN c_failure;
  END IF;
END invalid_laf_check;


FUNCTION depend_usr_tables_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null varchar2(1);
BEGIN
  -- Look for any user tables dependent on Oracle-Maintained types.
  -- If there are any, then IF the -T option is used to set user tablespaces to
  -- READ ONLY during the upgrade, then a post-upgrade action to run 
  -- utluptabdata.sql is required.

 IF sys.dbms_registry.release_version = '&C_ORACLE_HIGH_VERSION_4_DOTS' THEN
   -- Perform post-upgrade check:
   --   If -T has NOT been used, then all tables should be already upgraded.
   --   If -T was used, and utluptabdata.sql was run successfully, then all
   --       tables should already be upgraded. 
   --   If -T was used but utluptabdata.sql was NOT run to upgrade all of the
   --       remaining tables, then this check will fail post upgrade.
   SELECT NULL into t_null
   FROM sys.obj$ o, sys.user$ u, sys.col$ c, sys.coltype$ t
   WHERE bitand(t.flags,256) = 256 AND -- UPGRADED = NO
         t.intcol# = c.intcol# AND
         t.col# = c.col# AND
         t.obj# = c.obj# AND
         c.obj# = o.obj# AND
         o.owner# = u.user# AND
         o.owner# NOT IN -- Not an Oracle-Supplied user
            (SELECT user# FROM sys.user$
             WHERE type#=1 AND bitand(spare1, 256)= 256) AND
         o.obj# IN  -- A dependent of an Oracle-Maintained type
            (SELECT d.d_obj#  
             FROM sys.dependency$ d, sys.obj$ do
             WHERE do.obj# = d.d_obj#
               AND do.type# IN (2,13)
             START WITH d.p_obj# IN -- Oracle-Maintained types
                (SELECT obj# from sys.obj$ 
                 WHERE type#=13 AND 
                       owner# IN -- an Oracle-Supplied user 
                           (SELECT user# FROM sys.user$
                            WHERE type#=1 AND 
                            bitand(spare1, 256)= 256))             
             CONNECT BY NOCYCLE PRIOR d.d_obj# = d.p_obj#);
  -- Found a dependent table
  result_txt := get_failed_check_xml('depend_usr_tables',
                      new string_array_t(db_version_4_dots),
                      null, null);
  RETURN c_failure;   

 ELSE -- Perform preupgrade check
  SELECT NULL into t_null
  FROM sys.obj$
  WHERE type# = 2
    AND owner# NOT IN 
       (SELECT schema# FROM sys.registry$ WHERE namespace = 'SERVER'
        UNION
        SELECT schema# FROM sys.registry$schemas WHERE namespace = 'SERVER'
        UNION
        SELECT user# FROM user$ WHERE type#=1 AND bitand(spare1,256)=256)
    AND obj# IN
        (SELECT do.obj# FROM sys.dependency$ d, sys.obj$ do
          WHERE do.obj# = d.d_obj#
            AND do.type# IN (2,13)
         START WITH d.p_obj# IN -- Oracle-Maintained types
           (SELECT obj# from sys.obj$ 
            WHERE type#=13  
              AND owner# IN
                 (SELECT schema# FROM sys.registry$ 
                  WHERE namespace = 'SERVER'
                  UNION
                  SELECT schema# FROM sys.registry$schemas 
                  WHERE namespace = 'SERVER'
                  UNION
                  SELECT user# FROM sys.user$
                  WHERE type#=1 AND bitand(spare1,256)=256))
         CONNECT BY NOCYCLE PRIOR d.d_obj# = d.p_obj#)
    AND rownum <=1;
  -- Found a dependent table
  result_txt := get_failed_check_xml('depend_usr_tables',
                      new string_array_t(db_version_4_dots),
                      null, null);
  RETURN c_failure;   
 END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN 
     -- No rows found, so no dependent tables
     RETURN c_success;
  WHEN OTHERS THEN
     result_txt := get_failed_check_xml('depend_usr_tables',
                         new string_array_t(db_version_4_dots),
                         null, null);
     RETURN c_failure;   
END depend_usr_tables_check;

--
-- Post upgrade Fixup depend_usr_tables_fixup
--
FUNCTION depend_usr_tables_fixup (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN NUMBER
IS
  t_full_name  VARCHAR2(256);
  t_sqltxt     VARCHAR2(4000);
  t_new_err    VARCHAR2(500);
  t_error      BOOLEAN := FALSE;
  t_took_error BOOLEAN := FALSE;
  t_sqlcode    NUMBER;  -- The last sql error we took
  t_len        NUMBER;
  CURSOR t_tabs IS
     SELECT DISTINCT u.name owner, o.name name
     FROM sys.obj$ o, sys.user$ u, sys.col$ c, sys.coltype$ t
     WHERE bitand(t.flags,256) = 256 -- DATA_UPGRADED = 'NO'
       AND t.intcol# = c.intcol# AND t.col# = c.col#
       AND t.obj# = c.obj# AND  c.obj# = o.obj# 
       AND o.owner# = u.user# AND o.type# = 2
       AND o.owner# NOT IN  -- Not an Oracle-Supplied user
           (SELECT user# FROM sys.user$ 
            WHERE type#=1 AND bitand(spare1,256)=256)
       AND  o.obj# IN  -- A dependent of an Oracle-mainted type
           (SELECT do.obj# 
            FROM sys.dependency$ d, sys.obj$ do
            WHERE do.obj# = d.d_obj#
              AND do.type# IN (2,13)
            START WITH d.p_obj# IN 
                (SELECT obj# from sys.obj$ 
                 WHERE type#=13 AND owner# IN
                   (SELECT schema# FROM sys.registry$ 
                    WHERE namespace = 'SERVER'
                    UNION
                    SELECT schema# FROM sys.registry$schemas 
                    WHERE namespace = 'SERVER'
                    UNION
                    SELECT user# FROM sys.user$ 
                    WHERE type#=1 AND bitand(spare1,256)=256))
              CONNECT BY NOCYCLE PRIOR d.d_obj# = d.p_obj#);
BEGIN
  result_txt := '';

  FOR tab IN t_tabs LOOP
    --
    -- Put quotes around the schema and table name
    --
    t_full_name :=  dbms_assert.enquote_name(tab.owner, FALSE) || '.' ||
                    dbms_assert.enquote_name(tab.name,FALSE);
    BEGIN
      EXECUTE IMMEDIATE 'ALTER TABLE ' || t_full_name
                || ' UPGRADE INCLUDING DATA';
      EXCEPTION WHEN OTHERS THEN
        t_error  := TRUE;
        t_sqltxt := SQLERRM;
        t_sqlcode  := SQLCODE;
        t_took_error := TRUE;
    END;

    IF t_error THEN
      IF result_txt != '' THEN
        -- If not the first, add a crlf
        result_txt := result_txt || crlf;
      END IF;

      t_new_err :=
            '  Error upgrading: ' || t_full_name || crlf ||
            '  Error Text:      ' || t_sqltxt || crlf;

      --
      --  length returns NULL (and not zero) for null varchar2's
      --
      t_len := NVL(length(result_txt), 0);

      IF (t_len + length (t_new_err) <= c_str_max) THEN
        --
        -- will fit into our buffer
        --
        result_txt := result_txt || t_new_err;
      ELSE
        t_new_err := crlf ||
           '  *** Too Many Tables ***' || crlf ||
           '  *** Run rdbms/admin/utluptabdata.sql instead *** ';
        --
        -- see if this will fit on the end (should be
        -- shorter than the actual error)
        --
        IF (t_len + length (t_new_err) < c_str_max) THEN
          -- Fits
          result_txt := result_txt || t_new_err;
        ELSE
          --
          -- Won't fit, cut some off and add the above error
          --
          result_txt := substr (result_txt, 1, t_len -
                                    length(t_new_err));
          result_txt := result_txt || t_new_err;
        END IF;
        -- We are done.
        EXIT;   -- Out of the loop
      END IF;
      t_error := FALSE;  -- Reset error
    END IF;
  END LOOP;

  IF t_took_error THEN
    pSqlcode := t_sqlcode;  -- Return the last failure code
    RETURN c_failure;
  ELSE
    RETURN c_success;
  END IF;
END depend_usr_tables_fixup;

FUNCTION invalid_usr_tabledata_check    (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null  NUMBER;
BEGIN
  --
  -- Include only tables dependent on Oracle-Maintained types
  -- by looking through dependency$ for types owned by schemas in
  -- registry$ or user$ (12.1) Oracle-Maintained flag.
 BEGIN
  SELECT NULL into t_null
  FROM SYS.OBJ$ o, SYS.COL$ c, SYS.COLTYPE$ t
  WHERE BITAND(t.FLAGS, 256) = 256 -- DATA_UPGRADED = NO
    AND o.OBJ# = t.OBJ# AND c.OBJ# = t.OBJ# 
    AND c.COL# = t.COL# AND t.INTCOL# = c.INTCOL#
    AND o.type# = 2 AND o.owner# NOT IN  -- Not an Oracle-Supplied user
       (SELECT schema# FROM sys.registry$ WHERE namespace = 'SERVER'
        UNION
        SELECT schema# FROM sys.registry$schemas WHERE namespace = 'SERVER'
        UNION
        SELECT user# FROM user$ WHERE type#=1 AND bitand(spare1,256)=256)
    AND o.obj# IN  --A dependent of an Oracle-maintained type
        (SELECT do.obj# 
         FROM sys.dependency$ d, sys.obj$ do
         WHERE do.obj# = d.d_obj#
           AND do.type# IN (2,13)
         START WITH d.p_obj# IN 
          (SELECT obj# from sys.obj$
           WHERE type#=13 AND owner# IN
             (SELECT schema# FROM sys.registry$ WHERE namespace = 'SERVER'
              UNION
              SELECT schema# FROM sys.registry$schemas WHERE namespace = 'SERVER'
              UNION
              SELECT user# FROM user$ WHERE type#=1 AND bitand(spare1,256)=256))
        CONNECT BY NOCYCLE PRIOR d.d_obj# = d.p_obj#)
    AND ROWNUM <=1;
    -- A row found, so the check fails
    result_txt := get_failed_check_xml('invalid_usr_tabledata',
                  new string_array_t(db_version_4_dots),
                  null, null);
    RETURN c_failure;
 EXCEPTION  -- No user tables dependent on Oracle-Maintained types need upgrading
    WHEN NO_DATA_FOUND THEN RETURN c_success;
    WHEN OTHERS THEN
        result_txt := get_failed_check_xml('invalid_usr_tabledata',
                  new string_array_t(db_version_4_dots),
                  null, null);
        RETURN c_failure;
 END;
END invalid_usr_tabledata_check;

--
-- Fixup invalid_usr_tabledata_fixup
--
FUNCTION invalid_usr_tabledata_fixup (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN NUMBER
IS
  t_full_name  VARCHAR2(256);
  t_sqltxt     VARCHAR2(4000);
  t_new_err    VARCHAR2(500);
  t_error      BOOLEAN := FALSE;
  t_took_error BOOLEAN := FALSE;
  t_sqlcode    NUMBER;  -- The last sql error we took
  t_len        NUMBER;
  CURSOR t_tabs IS
     SELECT DISTINCT u.name owner, o.name name
     FROM sys.obj$ o, sys.user$ u, sys.col$ c, sys.coltype$ t
     WHERE bitand(t.flags,256) = 256 -- DATA_UPGRADED = 'NO'
       AND t.intcol# = c.intcol# AND t.col# = c.col#
       AND t.obj# = c.obj# AND  c.obj# = o.obj# 
       AND o.owner# = u.user# AND o.type# = 2
       AND o.owner# NOT IN  -- Not an Oracle-Supplied user
             (SELECT schema# FROM sys.registry$ WHERE namespace = 'SERVER'
              UNION
              SELECT schema# FROM sys.registry$schemas WHERE namespace = 'SERVER'
              UNION
              SELECT user# FROM sys.user$ WHERE type#=1 AND bitand(spare1,256)=256)
       AND  o.obj# IN  -- A dependent of an Oracle-mainted type
           (SELECT do.obj# 
            FROM sys.dependency$ d, sys.obj$ do
            WHERE do.obj# = d.d_obj#
              AND do.type# IN (2,13)
            START WITH d.p_obj# IN 
                (SELECT obj# from sys.obj$ 
                 WHERE type#=13 AND owner# IN
                   (SELECT schema# FROM sys.registry$ 
                    WHERE namespace = 'SERVER'
                    UNION
                    SELECT schema# FROM sys.registry$schemas 
                    WHERE namespace = 'SERVER'
                    UNION
                    SELECT user# FROM sys.user$ 
                    WHERE type#=1 AND bitand(spare1,256)=256))
              CONNECT BY NOCYCLE PRIOR d.d_obj# = d.p_obj#);
BEGIN
  result_txt := '';

  FOR tab IN t_tabs LOOP
    --
    -- Put quotes around the schema and table name
    --
    t_full_name :=  dbms_assert.enquote_name(tab.owner, FALSE) || '.' ||
                    dbms_assert.enquote_name(tab.name,FALSE);
    BEGIN
      EXECUTE IMMEDIATE 'ALTER TABLE ' || t_full_name
                || ' UPGRADE INCLUDING DATA';
      EXCEPTION WHEN OTHERS THEN
        t_error  := TRUE;
        t_sqltxt := SQLERRM;
        t_sqlcode  := SQLCODE;
        t_took_error := TRUE;
    END;

    IF t_error THEN
      IF result_txt != '' THEN
        -- If not the first, add a crlf
        result_txt := result_txt || crlf;
      END IF;

      t_new_err :=
            '  Error upgrading: ' || t_full_name || crlf ||
            '  Error Text:      ' || t_sqltxt || crlf;

      --
      --  length returns NULL (and not zero) for null varchar2's
      --
      t_len := NVL(length(result_txt), 0);

      IF (t_len + length (t_new_err) <= c_str_max) THEN
        --
        -- will fit into our buffer
        --
        result_txt := result_txt || t_new_err;
      ELSE
        t_new_err := crlf ||
           '  *** Too Many Tables ***' || crlf ||
           '  *** Cleanup and re-execute to see more tables *** ';
        --
        -- see if this will fit on the end (should be
        -- shorter than the actual error)
        --
        IF (t_len + length (t_new_err) < c_str_max) THEN
          -- Fits
          result_txt := result_txt || t_new_err;
        ELSE
          --
          -- Won't fit, cut some off and add the above error
          --
          result_txt := substr (result_txt, 1, t_len -
                                    length(t_new_err));
          result_txt := result_txt || t_new_err;
        END IF;
        -- We are done.
        EXIT;   -- Out of the loop
      END IF;
      t_error := FALSE;  -- Reset error
    END IF;
  END LOOP;

  IF t_took_error THEN
    pSqlcode := t_sqlcode;  -- Return the last failure code
    RETURN c_failure;
  ELSE
    RETURN c_success;
  END IF;
END invalid_usr_tabledata_fixup;

FUNCTION invalid_sys_tabledata_check    (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null  NUMBER;
BEGIN
  -- Use schemas from registry$ tables and from user$ (12.1)
  SELECT NULL INTO t_null
  FROM sys.obj$ o, sys.col$ c, sys.coltype$ t       
  WHERE BITAND(t.flags, 256) = 256 -- DATA_UPGRADED = NO            
    AND o.obj# = t.obj# AND c.OBJ# = t.obj#         
    AND c.COL# = t.col# AND t.intcol# = c.intcol#   
    AND o.type# = 2 AND o.owner# IN                 
       (SELECT schema# FROM sys.registry$ WHERE namespace = 'SERVER'               
        UNION                                         
        SELECT schema# FROM sys.registry$schemas WHERE namespace = 'SERVER'
        UNION
        SELECT user# FROM user$ WHERE type#=1 AND bitand(spare1,256)=256)
    AND ROWNUM <=1;
    -- An Oracle-Supplied table needing to be upgraded has been found
  result_txt := get_failed_check_xml('invalid_sys_tabledata',
                      new string_array_t(db_version_4_dots),
                      null, null);
  RETURN c_failure;
EXCEPTION
  WHEN NO_DATA_FOUND THEN RETURN c_success;
END invalid_sys_tabledata_check;

--
-- Fixup invalid_sys_tabledata_fixup
--
FUNCTION invalid_sys_tabledata_fixup (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN number
IS
  t_full_name  VARCHAR2(261); -- extra for quotes and . 
  t_sqltxt     VARCHAR2(4000);
  t_new_err    VARCHAR2(500);
  t_error      BOOLEAN := FALSE;
  t_took_error BOOLEAN := FALSE;
  t_sqlcode    NUMBER;  -- The last sql error we took
  t_len        NUMBER;
  CURSOR t_tabs IS
     SELECT DISTINCT u.name owner, o.name name
     FROM sys.obj$ o, sys.user$ u, sys.col$ c, sys.coltype$ t
     WHERE bitand(t.flags,256) = 256  -- NOT upgraded
       AND t.intcol# = c.intcol# AND t.col# = c.col# 
       AND t.obj# = c.obj# AND c.obj# = o.obj# 
       AND o.type# = 2 AND o.owner# = u.user#
       AND o.owner# IN 
          (SELECT distinct schema# FROM sys.registry$ WHERE NAMESPACE = 'SERVER'
           UNION 
           SELECT DISTINCT schema# FROM sys.registry$schemas WHERE NAMESPACE = 'SERVER'
           UNION
           SELECT user# FROM user$ WHERE type#=1 AND bitand(spare1,256)=256);
BEGIN
  result_txt := '';

  FOR tab IN t_tabs LOOP
    BEGIN
      t_full_name :=  dbms_assert.enquote_name(tab.owner, FALSE) || '.' || 
                      dbms_assert.enquote_name(tab.name,FALSE);
      EXECUTE IMMEDIATE 'ALTER TABLE ' ||  t_full_name 
                 || ' UPGRADE INCLUDING DATA';
      EXCEPTION WHEN OTHERS THEN
        t_error  := TRUE;
        t_sqltxt := SQLERRM;
        t_sqlcode  := SQLCODE;
        t_took_error := TRUE;
    END;

    IF t_error THEN
      IF result_txt != '' THEN
        -- If not the first, add a crlf
        result_txt := result_txt || crlf;
      END IF;

      t_new_err := 
            '  Error upgrading: ' || t_full_name || crlf ||
            '  Error Text:      ' || t_sqltxt || crlf;

      --
      --  length returns NULL (and not zero) for null varchar2's 
      --
      t_len := NVL(length(result_txt), 0);

      IF (t_len + length (t_new_err) <= c_str_max) THEN
        --
        -- will fit into our buffer
        --
        result_txt := result_txt || t_new_err;
      ELSE
        t_new_err := crlf || 
           '  *** Too Many Tables ***' || crlf ||
           '  *** Cleanup and re-execute to see more tables *** ';
        --
        -- see if this will fit on the end (should be 
        -- shorter than the actual error)
        --
        IF (t_len + length (t_new_err) < c_str_max) THEN
          -- Fits
          result_txt := result_txt || t_new_err;  
        ELSE 
          -- 
          -- Won't fit, cut some off and add the above error
          --
          result_txt := substr (result_txt, 1, t_len - 
                              length(t_new_err) - 1);
          result_txt := result_txt || t_new_err;
        END IF;
        -- We are done.
        EXIT;   -- Out of the loop
      END IF;
      t_error := FALSE;  -- Reset error
    END IF;
  END LOOP;

  IF t_took_error THEN
    pSqlcode := t_sqlcode;  -- Return the last failure code
    return c_failure;
  ELSE
    return c_success;
  END IF;
END;

FUNCTION enabled_indexes_tbl_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  status  NUMBER := 0;
  t_count   INTEGER;
BEGIN
    --
    -- Check for pre-existing temporary table sys.enabled$indexes.
    -- If it exists, then warn the user to DROP SYS.ENABLED$INDEXES.
    --
    BEGIN
        EXECUTE IMMEDIATE 'SELECT COUNT(1) FROM sys.enabled$indexes'
        INTO t_count;
        IF (t_count >= 0) THEN
            status := 1;
        END IF;
    EXCEPTION
        WHEN OTHERS THEN NULL;
    END;

    IF (status = 0) THEN
        RETURN c_success;
    ELSE
         result_txt := get_failed_check_xml('enabled_indexes_tbl',
                      new string_array_t(),
                      null, null);
	return c_failure;
   END IF;
END enabled_indexes_tbl_check;

--
-- Fixup enabled_indexes_tbl_fixup
--
FUNCTION enabled_indexes_tbl_fixup (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN NUMBER
IS
    drop_result BOOLEAN;
BEGIN
   drop_result := execute_sql_statement ('DROP TABLE sys.enabled$indexes', result_txt, pSqlcode);
   IF drop_result THEN
       RETURN c_success;
   ELSE
       RETURN c_failure;
   END IF;
END enabled_indexes_tbl_fixup;



FUNCTION ordimageindex_check            (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_count NUMBER := 0;
  status  NUMBER;
BEGIN
  --
  -- The upgrade will remove them, so the misc warning section will
  -- let them know.
  --
  BEGIN
    EXECUTE IMMEDIATE
     'SELECT COUNT(*) FROM sys.dba_indexes WHERE index_type = ''DOMAIN''
         and ityp_name = ''ORDIMAGEINDEX'''
   INTO t_count;
  EXCEPTION
     WHEN OTHERS THEN NULL;
  END;

  IF (t_count = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('ordimageindex',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS),
                      null, null);
    RETURN c_failure;
   END IF;
END ordimageindex_check;



FUNCTION invalid_objects_exist_check    (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null              CHAR(1);
  invalid_objs        BOOLEAN := FALSE;
  t_invalid_objs      NUMBER;
BEGIN
  --
  -- Check for INVALID objects
  -- For "inplace" upgrades check for invalid objects that can be excluded
  -- as they may have changed between releases and don't need to be reported.
  --
  -- For all other types of upgrades, use the simple query below to
  -- eliminate running the intricate queries except when they are needed.
  --
  BEGIN
    IF NOT db_inplace_upgrade  THEN
      EXECUTE IMMEDIATE 'SELECT NULL FROM sys.dba_objects
          WHERE status = ''INVALID'' AND object_name NOT LIKE ''BIN$%'' AND
             rownum <=1'
      INTO t_null;
      -- For patch release - update the objects in the query below
    ELSE
      -- V_$ROLLNAME special cased because of references  to x$ tables
      EXECUTE IMMEDIATE 'SELECT NULL FROM SYS.DBA_OBJECTS
           WHERE status = ''INVALID'' AND object_name NOT LIKE ''BIN$%'' AND
              rownum <=1 AND
              object_name NOT IN
                 (SELECT name FROM SYS.dba_dependencies
                    START WITH referenced_name IN (
                         ''V$LOGMNR_SESSION'', ''V$ACTIVE_SESSION_HISTORY'',
                         ''V$BUFFERED_SUBSCRIBERS'',  ''GV$FLASH_RECOVERY_AREA_USAGE'',
                         ''GV$ACTIVE_SESSION_HISTORY'', ''GV$BUFFERED_SUBSCRIBERS'',
                         ''V$RSRC_PLAN'', ''V$SUBSCR_REGISTRATION_STATS'',
                         ''GV$STREAMS_APPLY_READER'',''GV$ARCHIVE_DEST'',
                         ''GV$LOCK'',''DBMS_STATS_INTERNAL'',''V$STREAMS_MESSAGE_TRACKING'',
                         ''GV$SQL_SHARED_CURSOR'',''V$RMAN_COMPRESSION_ALGORITHM'',
                         ''V$RSRC_CONS_GROUP_HISTORY'',''V$PERSISTENT_SUBSCRIBERS'',''V$RMAN_STATUS'',
                         ''GV$RSRC_CONSUMER_GROUP'',''V$ARCHIVE_DEST'',''GV$RSRCMGRMETRIC'',
                         ''GV$RSRCMGRMETRIC_HISTORY'',''V$PERSISTENT_QUEUES'',''GV$CPOOL_CONN_INFO'',
                         ''GV$RMAN_COMPRESSION_ALGORITHM'',''DBA_BLOCKERS'',''V$STREAMS_TRANSACTION'',
                         ''V$STREAMS_APPLY_READER'',''GV$SGA_DYNAMIC_FREE_MEMORY'',''GV$BUFFERED_QUEUES'',
                         ''GV$RSRC_PLAN_HISTORY'',''GV$ENCRYPTED_TABLESPACES'',''V$ENCRYPTED_TABLESPACES'',
                         ''GV$RSRC_CONS_GROUP_HISTORY'',''GV$RSRC_PLAN'',
                         ''GV$RSRC_SESSION_INFO'',''V$RSRCMGRMETRIC'',''V$STREAMS_CAPTURE'',
                         ''V$RSRCMGRMETRIC_HISTORY'',''GV$STREAMS_TRANSACTION'',''DBMS_LOGREP_UTIL'',
                         ''V$RSRC_SESSION_INFO'',''GV$STREAMS_CAPTURE'',''V$RSRC_PLAN_HISTORY'',
                         ''GV$FLASHBACK_DATABASE_LOGFILE'',''V$BUFFERED_QUEUES'',
                         ''GV$PERSISTENT_SUBSCRIBERS'',''GV$FILESTAT'',''GV$STREAMS_MESSAGE_TRACKING'',
                         ''V$RSRC_CONSUMER_GROUP'',''V$CPOOL_CONN_INFO'',''DBA_DML_LOCKS'',
                         ''V$FLASHBACK_DATABASE_LOGFILE'',''GV$HM_RECOMMENDATION'',
                         ''V$SQL_SHARED_CURSOR'',''GV$PERSISTENT_QUEUES'',''GV$FILE_HISTOGRAM'',
                         ''DBA_WAITERS'',''GV$SUBSCR_REGISTRATION_STATS'')
                                AND referenced_type in (''VIEW'',''PACKAGE'') OR
                          name = ''V_$ROLLNAME''
                             CONNECT BY
                               PRIOR name = referenced_name and
                               PRIOR type = referenced_type)'
      INTO t_null;
    END IF;
    invalid_objs := TRUE;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN NULL;
  END;

 -- look for invalid objects
  EXECUTE IMMEDIATE 'SELECT count(*) FROM sys.dba_objects 
  WHERE status !=''VALID'' ' INTO t_invalid_objs;

  --
  -- Now get back to reporting the issue if we need to.
  --
  IF invalid_objs = FALSE THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('invalid_objects_exist',
                      new string_array_t(db_version_4_dots, t_invalid_objs),
                      null, null);

    RETURN c_failure;
  END IF;
END invalid_objects_exist_check;


FUNCTION amd_exists_check               (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  n_status NUMBER := -1;
BEGIN
  --
  -- Is AMD around?
  --
  BEGIN
    EXECUTE IMMEDIATE
       'SELECT  status FROM sys.registry$ WHERE cid=''AMD''
          AND namespace=''SERVER'''
       INTO n_status;
  EXCEPTION
      WHEN OTHERS THEN NULL; -- AMD not in registry
  END;

  IF (n_status = -1) THEN
    -- AMD not in registry
    -- or output is XML, return success
    RETURN c_success;
  END IF;

  --
  -- This is a manual only check
  --
  result_txt := get_failed_check_xml('amd_exists',
                    new string_array_t(db_version_4_dots),
                    null, null);

  RETURN c_failure;
END amd_exists_check;


FUNCTION exf_rul_exists_check           (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  n_status NUMBER := -1;
BEGIN
  --
  -- See if EXF and/or RUL components exist, they will be
  -- removed during the upgrade so let them know they can remove them
  -- before the upgrade.
  --
  BEGIN
    EXECUTE IMMEDIATE
       'SELECT  status FROM sys.registry$ WHERE (cid=''RUL'' OR cid=''EXF'')
          WHERE namespace=''SERVER'''
       INTO n_status;
  EXCEPTION
      WHEN OTHERS THEN NULL; -- EXF or RUL not in registry
  END;

  IF (n_status = -1) THEN
    --
    -- does not exist
    --
    RETURN c_success;
  END IF;

  result_txt := get_failed_check_xml('exf_rul_exists',
                    new string_array_t(),
                    null, null);

  RETURN c_failure;
END exf_rul_exists_check;


FUNCTION new_time_zones_exist_check     (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  status NUMBER;
BEGIN
  IF (db_tz_version <= &C_LTZ_CONTENT_VER) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('new_time_zones_exist',
                    new string_array_t(db_version_4_dots, to_char(db_tz_version),C_ORACLE_HIGH_VERSION_4_DOTS,to_char(&C_LTZ_CONTENT_VER)),
                    null, null);
    RETURN c_failure;
  END IF;
END new_time_zones_exist_check;


FUNCTION old_time_zones_exist_check     (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  status  NUMBER;
BEGIN
  --
  -- Do we have a valid time zone for an upgrade
  --
  IF (db_tz_version >= &C_LTZ_CONTENT_VER) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('old_time_zones_exist',
                    new string_array_t(db_version_4_dots, to_char(db_tz_version),C_ORACLE_HIGH_VERSION_4_DOTS,to_char(&C_LTZ_CONTENT_VER)),
                    null, null);
    RETURN c_failure;
  END IF;
END old_time_zones_exist_check;


FUNCTION purge_recyclebin_check         (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  obj_count NUMBER;
BEGIN
   EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM sys.recyclebin$'
     INTO obj_count;

  IF (obj_count = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('purge_recyclebin',
                    new string_array_t(to_char(obj_count)),
                    null, null);
    RETURN c_failure;
  END IF;
END purge_recyclebin_check;

FUNCTION purge_recyclebin_fixup (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN number
IS
    fixup_result BOOLEAN;
BEGIN
   fixup_result := execute_sql_statement ('PURGE DBA_RECYCLEBIN', result_txt, pSqlcode);
   if fixup_result then
      return c_success;
   else
      return c_failure;
   end if;
END purge_recyclebin_fixup;


FUNCTION job_queue_process_0_check        (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  p_count  NUMBER := -1;
  status   NUMBER;
  idx      NUMBER;
  p_lowest NUMBER;
  edetails VARCHAR2(500);

BEGIN
  BEGIN
    EXECUTE IMMEDIATE 'SELECT value FROM v$parameter WHERE
          name=''job_queue_processes'''
    INTO p_count;
  EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
  END;

  IF (p_count <> 0) THEN
    RETURN c_success;
  ELSE
    p_lowest := 0;

    result_txt := get_failed_check_xml('job_queue_process_0',
                    new string_array_t(to_char(p_lowest)),
                    null, null);

    RETURN c_failure;
  END IF;
END job_queue_process_0_check;

FUNCTION job_queue_process_check        (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  p_count  NUMBER := -1;
  status   NUMBER;
  idx      NUMBER;
  p_lowest NUMBER;
  edetails VARCHAR2(500);

BEGIN
  --
  --    This CHECK will not take action if JOB_QUEUE_PROCESSES=0.
  --    That case will be handled by another CHECK, JOB_QUEUE_PROCESS_0
  --
  BEGIN
    EXECUTE IMMEDIATE 'SELECT value FROM v$parameter WHERE
          name=''job_queue_processes'''
    INTO p_count;
  EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
  END;

  p_lowest := 0;

  --
  -- If we failed to grab the count (not set),
  -- or the count is > the number of cpu*threads then
  -- there is no error
  --
  IF (p_count < 1) OR (p_count > p_lowest) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('job_queue_process',
                    new string_array_t(to_char(p_count), to_char(p_lowest)),
                    null, null);
    RETURN c_failure;
  END IF;
END job_queue_process_check;


FUNCTION upg_by_std_upgrd_check     (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  my_components_list VARCHAR2(4000) := ' ';
  not_my_components_list VARCHAR2(4000) := ' ';
  all_components_mine BOOLEAN := TRUE;
  not_my_comps_cursor cursor_t;
  c_cname SYS.REGISTRY$.CNAME%TYPE;
  select_stmt VARCHAR2(500);
BEGIN
  BEGIN
    -- construct a quoted and comma separated list of components that will
    -- be upgraded by the upgrade script.
    -- since the list of my components is known, this code won't overflow
    -- the my_components_list stringsize
    FOR i in 1..max_components_less_misc LOOP
        if (i > 1) THEN
            my_components_list := my_components_list || ',';
        END IF;
        IF debug THEN
            dbms_output.put_line('In upg_by_std_upgrd check,i=' || to_char(i));
        END IF;

        my_components_list := my_components_list || dbms_assert.enquote_literal(cmp_info(i).cid);
    END LOOP;

    IF debug THEN
        dbms_output.put_line('In upg_by_std_upgrd check, my_components_list=' || my_components_list);
    END IF;

    select_stmt := 'SELECT cname FROM sys.registry$ WHERE namespace=' ||
                   dbms_assert.enquote_literal('SERVER') ||
                   ' AND cid NOT IN (' ||
                   my_components_list ||
                   ')';
    OPEN not_my_comps_cursor FOR select_stmt;

    LOOP
        FETCH not_my_comps_cursor INTO c_cname;
        EXIT WHEN not_my_comps_cursor%NOTFOUND;

        IF debug THEN
            dbms_output.put_line('In upg_by_std_upgrd check, processing non-std component: ' || c_cname);
        END IF;

        IF (LENGTH(not_my_components_list) >= (c_str_max-length(c_cname)-12)) THEN
            -- the 12 above is the length of ' plus others ' below.  Save space for it
            -- in case we need it.
            not_my_components_list := not_my_components_list || ' plus others';
            EXIT;
        ELSE
            IF (NOT all_components_mine) THEN
                not_my_components_list := not_my_components_list || ',';
            END IF;
            not_my_components_list := not_my_components_list || c_cname;
        END IF;
        all_components_mine := FALSE;
    END LOOP;
    CLOSE not_my_comps_cursor;
  END;
  IF (all_components_mine) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('upg_by_std_upgrd',
                    new string_array_t(not_my_components_list),
                    null, null);


    RETURN c_failure;
  END IF;
END upg_by_std_upgrd_check;


--
--     open_cursors Section
--
-- 1) If APEX is in the registry, then check the value of open_cursors.
--    Alert only if open_cursors is < 150.
--    This is an error condition check as APEX upgrades to 12102 can fail.
-- 2) If APEX is not in the registry, then no check is needed.
--
--
FUNCTION open_cursors_check             (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  open_cursors NUMBER;
  status       NUMBER;
  check_stmt   VARCHAR2(100);  -- stmt to execute in this open_cursors check
BEGIN

  -- query to execute in this open_cursors check
  check_stmt := 'select value from v$parameter where name=''open_cursors''';

  -- we only want to find out what open_cursors value is if apex is in db
  IF (cmp_info(apex).processed = TRUE) THEN  -- apex exists in registry$
    EXECUTE IMMEDIATE
      check_stmt
      INTO open_cursors;
  ELSE
    -- if apex is not in the registry, then no need to find out what
    -- the open_cursors value is.
    -- just go ahead and return success status.
    RETURN c_success;
  END IF;

  --
  -- open_cursors is bigger than min needed (and not debug) ->  return success
  --
  IF (open_cursors >= &C_MIN_OPEN_CURSORS) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('open_cursors',
                    new string_array_t(to_char(&C_MIN_OPEN_CURSORS),db_version_4_dots,to_char(open_cursors)),
                    null, null);
    RETURN c_failure;
  END IF;
END open_cursors_check;


FUNCTION xbrl_version_check             (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null      CHAR(1);
  status      NUMBER := 0;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE 'SELECT NULL FROM sys.user$ WHERE name=''XBRLSYS'''
      INTO t_null;
    status := 1;
    EXCEPTION
       WHEN NO_DATA_FOUND THEN NULL;
  END;

  IF (status = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('xbrl_version',
                    new string_array_t(),
                    null, null);
    RETURN c_failure;
  END IF;

END xbrl_version_check;


FUNCTION apex_patch_check               (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  db_full_apex_version VARCHAR2(40);
  apex_will_be_upgraded BOOLEAN;
  apex_patch_level_met BOOLEAN;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE
      'SELECT version FROM sys.registry$ WHERE cid = ''APEX'' and namespace=''SERVER'''
      INTO db_full_apex_version;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      -- no APEX, no problem.
      return c_success;
  END;
  
  --
  -- APEX has unusual upgrade and patching rules:
  -- The RDBMS server bundle upgrade scripts will only upgrade APEX if
  -- the version string prior to the second dot requires upgrade.  If not,
  -- no upgrade is done on APEX, and the user is left to manually "patch"
  -- APEX to bring it up to the full patch level of the software on the
  -- distribution kit, i.e. after the upgrade, APEX may not yet be at the
  -- full 4 dot version it needs to be.
  --
  apex_will_be_upgraded := (dbms_registry_extended.compare_versions(db_full_apex_version, high_version_apex, 1) < 0);
  apex_patch_level_met  := (dbms_registry_extended.compare_versions(db_full_apex_version, high_version_apex, 4) >= 0);

  IF (not apex_will_be_upgraded) and (not apex_patch_level_met) THEN
    result_txt := get_failed_check_xml('apex_patch',
                    new string_array_t(db_version_4_dots,
                                       high_version_apex,
                                       dbms_registry_extended.convert_version_to_n_dots(high_version_apex,1),
                                       db_full_apex_version),
                    null, null);
    return c_failure;
  ELSE
    return c_success;
  END IF;
END apex_patch_check;

FUNCTION apex_upgrade_msg_check         (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  db_full_apex_version VARCHAR2(40);
  apex_will_be_upgraded BOOLEAN;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE
      'SELECT version FROM sys.registry$ WHERE cid = ''APEX'' and namespace=''SERVER'''
      INTO db_full_apex_version;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      -- no APEX, no problem.
      return c_success;
  END;
  
  --
  -- APEX has unusual upgrade and patching rules:
  -- The RDBMS server bundle upgrade scripts will only upgrade APEX if
  -- the version string prior to the second dot requires upgrade.  If not,
  -- no upgrade is done on APEX.
  --
  apex_will_be_upgraded := (dbms_registry_extended.compare_versions(db_full_apex_version, high_version_apex, 1) < 0);

  IF apex_will_be_upgraded THEN
    result_txt := get_failed_check_xml('apex_upgrade_msg',
                    new string_array_t(db_full_apex_version, high_version_apex),
                    null, null);
    return c_failure;
  ELSE
    return c_success;
  END IF;
END apex_upgrade_msg_check;



-- *****************************************************************
--     default_resource_limit Section
--
-- 1) Initialization parameter RESOURCE_LIMIT 's default value is
--    changing from FALSE to TRUE starting in 12.1.0.2.
-- 2) Will warn customers about the default value changing.
--    This would only affect customers who have applied a resource limit
--    to a user and does not already have resource_limit set in their
--    parameter file.  If they don't have resource_limit set, which
--    means default is FALSE in pre-12102 but TRUE in 12102 and post-12102.
--
-- *****************************************************************
FUNCTION default_resource_limit_check   (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  ret_val      NUMBER := 0;     -- return value from check_stmt
  check_stmt   VARCHAR2(1000);  -- check if resource_limit warning is needed
BEGIN

  --
  --    RESOURCE_LIMIT warning is needed IF 1 is returned because all conditions
  --    are met:
  --    a) if RESOURCE_LIMIT init parameter is currently using the default value
  --       AND
  --    b) there are non-default/non-unlimited customized resource limits
  --       applied to 1 or more users
  --       AND
  --    c) db-to-be-upgraded's version is at 12.1.0.1 or older
  --
  check_stmt :=
    'SELECT 1 FROM sys.v$parameter ' ||
    'WHERE ' ||
    '( ' ||                                                 -- criteria (a)
    '    (upper(name) = ''RESOURCE_LIMIT'' AND isdefault = ''TRUE'') ' ||
    '  AND ' ||                                             -- criteria (b)
    '    0 < (SELECT count(*) ' ||
    '         FROM sys.dba_users ' ||
    '         WHERE profile in ' ||
    '           (SELECT unique(profile) ' ||
    '            FROM sys.dba_profiles ' ||
    '            WHERE resource_type = ''KERNEL'' and ' ||
    '                  limit not in (''UNLIMITED'', ''DEFAULT'')) ' ||
    '        ) ' ||
    '  AND ' ||                                             -- criteria (c)
    '    1 = (SELECT count(*) ' ||
    '         FROM sys.registry$ ' ||
    '         WHERE ' ||
    '           upper(cid) = ''CATPROC'' AND ' ||
    '           (substr(version, 1, 4) in (''10.2'', ''11.1'', ''11.2'') ' ||
    '            OR substr(version, 1, 8) = ''12.1.0.1'') ' ||
    '        ) ' ||
    ')';

  -- check if a warning - about RESOURCE_LIMIT defaulting to TRUE starting
  -- in 12102 - needs to be generated
  BEGIN
    EXECUTE IMMEDIATE
       check_stmt
       INTO ret_val;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      ret_val := 0;
    WHEN OTHERS THEN
      dbms_output.put_line('ORA' || SQLCODE ||
                           ': Error in DEFAULT_RESOURCE_LIMITS check_stmt:');
      dbms_output.put_line(SQLERRM);
  END; 

  -- return success status if check returns a 0
  -- i.e., don't generate warning if ret_val is 0 and do generate warning
  -- if ret_val is 1.
  IF (ret_val = 0) THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('default_resource_limit',
                    new string_array_t(db_version_4_dots),
                    null, null);

    RETURN c_failure;
  END IF;
END default_resource_limit_check;

--
-- BMMB
-- Bug 24923215: PREUPGADE TOOL TO SET_GLOBAL_PREFS('CONCURRENT','OFF'); FOR GATHER STATS
-- The conc_res_mgr check and its fixup handle when the Concurrent statistics preference
-- is enabled but Resoucer Manager is disabled.
--
FUNCTION conc_res_mgr_check             (result_txt OUT VARCHAR2) RETURN NUMBER
IS
    v_is_conc_on_boolean boolean := FALSE;
    v_is_res_man_on_boolean boolean := FALSE;
    v_conc_on_text varchar2(20);
    v_res_man_on_text V$PARAMETER.VALUE%TYPE;
    disable_conc_stats_text varchar2(75);
    
BEGIN
    --
    -- is concurrent preference set to on?
    -- 
    BEGIN
        EXECUTE IMMEDIATE
         'SELECT DBMS_STATS.GET_PREFS(''CONCURRENT'') FROM DUAL'
         INTO v_conc_on_text;
        
        -- 
        -- In 11.2 concurrent statistics preference had only two values, TRUE and FALSE.
        -- Starting 12.1 It can have four values: MANUAL, AUTOMATIC, ALL and OFF.
        -- FALSE or OFF mean that the concurrent preference is disabled
        IF (v_conc_on_text not in ('OFF', 'FALSE' )) THEN  -- If it is disabled.
            v_is_conc_on_boolean := TRUE;
        ELSE
            return c_success;  -- CONCURRENT STATS ARE DISABLED so we do not need to check anything further.        
        END IF;
        
    -- The query should return any value (FALSE OR OFF) if not it means 
    -- something happened at db level. Raise an exception.   
    END;
    --
    -- is Resourcer manager on?
    --
    BEGIN
        EXECUTE IMMEDIATE
         'select nvl(value, ''DISABLED'') from v$parameter where name = ''resource_manager_plan'''
         INTO v_res_man_on_text;
         
        IF (v_res_man_on_text != 'DISABLED') THEN
            v_is_res_man_on_boolean := TRUE;
        END IF;        
    -- IF Resource manager is disabled the query will return no values. 
    -- If there is any other error then raise an exception.
    END;
    
    IF (db_version_1_dot = '11.2') THEN
        disable_conc_stats_text := 'DBMS_STATS.SET_GLOBAL_PREFS(''CONCURRENT'',''FALSE'')';
    ELSE
        disable_conc_stats_text := 'DBMS_STATS.SET_GLOBAL_PREFS(''CONCURRENT'',''OFF'')';
    END IF;    
    
    --
    -- check if the concurrent statistics preferences is on
    -- and if Resource Manager is enabled
    -- The validation that will trigger the c_failure condition is:
    -- is_conc_pref is TRUE and is_res_man is FALSE
    --
    IF (v_is_conc_on_boolean AND NOT v_is_res_man_on_boolean) THEN
        result_txt := get_failed_check_xml('conc_res_mgr',
                    new string_array_t(v_conc_on_text, disable_conc_stats_text),
                    null, null);
        return c_failure;
    END IF;
    
    return c_success;
EXCEPTION WHEN NO_DATA_FOUND THEN
        internal_error('Could not determine the status of Concurrent statistics or Resource manager.');
    WHEN OTHERS THEN
        RAISE; 
           
END conc_res_mgr_check;

FUNCTION conc_res_mgr_fixup             (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number
IS
    disable_conc_stats_result BOOLEAN;
    disable_conc_stats_text varchar2(50);
BEGIN

  IF (db_version_1_dot = '11.2') THEN
    disable_conc_stats_text := 'DBMS_STATS.SET_GLOBAL_PREFS(''CONCURRENT'',''FALSE'')';
  ELSE
    disable_conc_stats_text := 'DBMS_STATS.SET_GLOBAL_PREFS(''CONCURRENT'',''OFF'')';
  END IF;

   disable_conc_stats_result := run_int_proc(disable_conc_stats_text, result_txt, pSqlcode);
   
   IF (disable_conc_stats_result) THEN
       RETURN c_success;
   ELSE
       RETURN c_failure;
   END IF; 

EXCEPTION WHEN OTHERS THEN 
    RAISE;    

END conc_res_mgr_fixup;

FUNCTION dictionary_stats_check         (result_txt OUT VARCHAR2) RETURN NUMBER
IS
dictionary_stats_recent  NUMBER := 0;
doc_name                 VARCHAR2(80) := '';  -- holds the name of the doc that
                                              -- points to the section on
                                              -- managing optimizer statistics

BEGIN

  BEGIN
    EXECUTE IMMEDIATE
     ' select 1 from dual where exists(
	      select distinct operation 
		from DBA_OPTSTAT_OPERATIONS 
			where operation =''gather_dictionary_stats'' 
			and start_time > systimestamp -  INTERVAL ''24''  HOUR) '
      INTO dictionary_stats_recent;
    EXCEPTION
      WHEN NO_DATA_FOUND then 
	null;
  END;

  IF (dictionary_stats_recent = 1)
  THEN
    RETURN c_success;
  ELSE

  doc_name := db_version_3_dots;
  IF (db_version_1_dot = '11.2') THEN
    doc_name := doc_name || ' Oracle Database Performance Tuning Guide';
  ELSIF (db_version_1_dot = '12.1' OR db_version_3_dots = '12.2.0.1') THEN
    doc_name := doc_name || ' Oracle Database SQL Tuning Guide';
  ELSE
    doc_name := doc_name || ' Oracle Database Upgrade Guide';
  END IF;

  result_txt := get_failed_check_xml('dictionary_stats',
                                      new string_array_t(doc_name),  -- {1}
                                      null, null);
  RETURN c_failure;


  END IF;
END dictionary_stats_check;


-- *****************************************************************
--     This fixup executes dictionary stats pre upgrade
-- *****************************************************************
FUNCTION dictionary_stats_fixup          (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN NUMBER
IS
    stats_result BOOLEAN;
    sys_string varchar2(5):='SYS';
BEGIN
   stats_result := run_int_proc('DBMS_STATS.GATHER_DICTIONARY_STATS', result_txt, pSqlcode);
   
   IF (stats_result) THEN
       RETURN c_success;
   ELSE
       RETURN c_failure;
   END IF; 
END dictionary_stats_fixup;

FUNCTION hidden_params_check            (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  hidden_params_cursor cursor_t;
  hidden_param SYS.V$PARAMETER.NAME%TYPE;
  hidden_param_count NUMBER := 0;
  hidden_params VARCHAR2(4000) := '';
BEGIN

    OPEN hidden_params_cursor FOR 'SELECT name FROM sys.v$parameter WHERE name LIKE ''\_%'' ESCAPE ''\'' AND ismodified != ''MODIFIED''';

    LOOP
        FETCH hidden_params_cursor INTO hidden_param;
        EXIT WHEN hidden_params_cursor%NOTFOUND;

        hidden_param_count := hidden_param_count + 1;
        IF (hidden_param_count > 1) THEN
            hidden_params := hidden_params || '<br>';
        END IF;
        -- more than 48 might cause overflow, max name length 80 chars 
        IF ( hidden_param_count > 48 ) THEN
            hidden_params := hidden_params || '(list truncated)';
            exit;
        ELSE
            hidden_params := hidden_params || hidden_param;
        END IF;
    END LOOP;
    CLOSE hidden_params_cursor;

    IF (hidden_param_count = 0) THEN
        RETURN c_success;
    ELSE
        result_txt := get_failed_check_xml('hidden_params',
                        new string_array_t(hidden_params),
                        null, null);
        RETURN c_failure;
    END IF;
END hidden_params_check;


FUNCTION underscore_events_check        (result_txt OUT VARCHAR2) RETURN NUMBER
IS
    underscore_event_count NUMBER := 0;
BEGIN
    --
    -- underscore events that are set.
    --
    BEGIN
      EXECUTE IMMEDIATE 'SELECT COUNT(1) FROM sys.v$parameter2 WHERE (UPPER(name) = ''EVENT''
           OR UPPER(name)=''_TRACE_EVENTS'') AND isdefault=''FALSE'''
      INTO underscore_event_count;
    EXCEPTION
      WHEN OTHERS THEN NULL;
    END;

    IF (underscore_event_count = 0) THEN
        RETURN c_success;
    ELSE
        result_txt := get_failed_check_xml('underscore_events',
                        new string_array_t(db_version_4_dots),
                        null, null);
        RETURN c_failure;
    END IF;
END underscore_events_check;


FUNCTION audit_records_check            (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_boolean BOOLEAN;
  t_status  NUMBER;
  audit_record_threshold NUMBER := 250000;
  audit_record_count NUMBER;
BEGIN
    t_boolean := FALSE;
    t_status := 0;
    -- There are three checks here - for various options of audit records.
    BEGIN
      EXECUTE IMMEDIATE 'SELECT count(*) FROM sys.aud$ WHERE dbid is null'
      INTO t_status;
      IF t_status > audit_record_threshold THEN
        t_boolean := TRUE;
        audit_record_count := t_status;
      END IF;
    EXCEPTION
      WHEN OTHERS THEN NULL;
    END;
    BEGIN
      -- Standard Auditing, only when Oracle Label Security (OLS)
      -- and/or Database Vault (DV) is installed
      EXECUTE IMMEDIATE 'SELECT count(*) FROM system.aud$ WHERE dbid is null'
      INTO t_status;
      IF t_status > audit_record_threshold THEN
        t_boolean := TRUE;
        audit_record_count := t_status;
    END IF;
    EXCEPTION
      WHEN OTHERS THEN NULL;
    END;
    BEGIN
      -- Fine Grained Auditing
      EXECUTE IMMEDIATE 'SELECT count(*) FROM sys.fga_log$ WHERE dbid is null'
      INTO t_status;
      IF t_status > audit_record_threshold THEN
        t_boolean := TRUE;
        audit_record_count := t_status;
      END IF;
    EXCEPTION
      WHEN OTHERS THEN NULL;
    END;

    IF t_boolean THEN
        result_txt := get_failed_check_xml('audit_records',
                        new string_array_t(db_version_4_dots,to_char(audit_record_count),to_char(audit_record_threshold)),
                        null, null);
        RETURN c_failure;
    ELSE
        RETURN c_success;
    END IF;
END audit_records_check;

-- *****************************************************************
--     FIXED_OBJECTS_CHECK Section
-- This check recommends gathering fixed objetcs stats post upgrade
-- *****************************************************************
FUNCTION fixed_objects_check            (result_txt OUT VARCHAR2) RETURN NUMBER
IS
fixed_objects_recent  NUMBER := 0;

BEGIN
-- this CHECK always fails... it always produces the recommendations.
    result_txt := get_failed_check_xml('fixed_objects',
                    new string_array_t(),
                    null, null);

    RETURN c_failure;
END fixed_objects_check;


-- *****************************************************************
--     POST_DICTIONARY_CHECK Section
--     This check recommends re-gathering dictionary stats post upgrade
--     The logic in the query is:  Check if statistics has been taken
--     after upgrade, if not report it and generate the fixup in the
--     postupgrade fixup script, after the fixup run, it will not fail
--     and therefore it will report this check as successfull.
-- *****************************************************************
FUNCTION post_dictionary_check          (result_txt OUT VARCHAR2) RETURN NUMBER
IS
dictionary_stats_recent  NUMBER := 0;
correct_version boolean := TRUE;

BEGIN
  IF dbms_registry_extended.compare_versions(db_version_4_dots, C_ORACLE_HIGH_VERSION_4_DOTS, 4) < 0 THEN
     correct_version := FALSE; 
  END IF;

  BEGIN
    EXECUTE IMMEDIATE
     ' select 1 from dual where exists(
	      select distinct operation 
		from DBA_OPTSTAT_OPERATIONS 
			where operation =''gather_dictionary_stats'' 
			and start_time > (select max(OPTIME) from registry$log where cid =''UPGRD_END'')) '
      INTO dictionary_stats_recent;
    EXCEPTION
      WHEN NO_DATA_FOUND then 
	null;
  END;

  IF (dictionary_stats_recent = 1  and correct_version)
  THEN
    RETURN c_success;
  ELSE
    -- this CHECK always fails... it always produces the recommendations.
    result_txt := get_failed_check_xml('post_dictionary',
                    new string_array_t(),
                    null, null);

    RETURN c_failure;
  END IF; 
END post_dictionary_check;

-- *****************************************************************
--     This fixup executes dictionary stats post upgrade
-- *****************************************************************
FUNCTION post_dictionary_fixup (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN NUMBER
IS
    stats_result BOOLEAN;
    sys_string varchar2(5):='SYS';
BEGIN
   stats_result := run_int_proc('DBMS_STATS.GATHER_DICTIONARY_STATS', result_txt, pSqlcode);
   IF (stats_result) THEN
       RETURN c_success;
   ELSE
       RETURN c_failure;
   END IF; 
END post_dictionary_fixup;


-- *****************************************************************
--     This function is meant to run any internal  procedure 
--     such as dbms_stats and others, calls execute_sql_statement
--     but let the function to run procedures and returns a boolean
--     to report if the procedure could run or not.
-- *****************************************************************

Function run_int_proc (statement VARCHAR2,
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN BOOLEAN
IS
    stats_result BOOLEAN;
BEGIN
   stats_result := execute_sql_statement ('begin '|| statement ||'; end;', 
                                           result_txt,   pSqlcode);
   RETURN stats_result;
END run_int_proc;

-- *****************************************************************
--     COMPATIBLE_NOT_SET_CHECK Section
-- This check verifies that the compatible parameter is defined,
-- if is not set, the check alerts to the user through an error
-- *****************************************************************
FUNCTION compatible_not_set_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
BEGIN
    -- TRUE means default, FALSE means parameter was set manually    
    IF (all_parameters.exists('compatible') AND
        all_parameters('compatible').isdefault = 'FALSE') THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('compatible_not_set',
                    new string_array_t(),
                    null, null);
    RETURN c_failure;
  END IF;
END compatible_not_set_check;


FUNCTION overlap_network_acl_check (result_txt OUT VARCHAR2) RETURN number
IS
  overlap_acl_exists NUMBER := 0;

BEGIN
  BEGIN
    EXECUTE IMMEDIATE
      'select 1 from dual where exists
      (select * from sys.net$_acl n1, sys.net$_acl n2
        where n1.host = n2.host and
        not (n1.lower_port = n2.lower_port and n2.upper_port = n1.upper_port) and
        ((n1.lower_port <= n2.lower_port and n2.lower_port <= n1.upper_port) or
         (n1.lower_port <= n2.upper_port and n2.upper_port <= n1.upper_port) or
         (n2.lower_port <= n1.lower_port and n1.lower_port <= n2.upper_port) or
         (n2.lower_port <= n1.upper_port and n1.upper_port <= n2.upper_port)))'
      INTO overlap_acl_exists;
  EXCEPTION
    WHEN OTHERS THEN NULL;
  END;

  IF (overlap_acl_exists = 0)
  THEN
    RETURN c_success;
  ELSE

  	result_txt := get_failed_check_xml('overlap_network_acl',
                  new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS),
                  'SQL',
                    'select n1.acl, n1.host, n1.lower_port, n1.upper_port '
                  ||'  from dba_network_acls n1 where exists '
                  ||'(select * from dba_network_acls n2 '
                  ||'  where n1.host = n2.host and '
                  ||'    not (n1.lower_port = n2.lower_port and n2.upper_port = n1.upper_port) and'
                  ||'    ((n1.lower_port <= n2.lower_port and n2.lower_port <= n1.upper_port) or'
                  ||'     (n1.lower_port <= n2.upper_port and n2.upper_port <= n1.upper_port) or'
                  ||'     (n2.lower_port <= n1.lower_port and n1.lower_port <= n2.upper_port) or'
                  ||'     (n2.lower_port <= n1.upper_port and n1.upper_port <= n2.upper_port)))'
                );
        RETURN c_failure;
  END IF;
END overlap_network_acl_check;


FUNCTION repcat_setup_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  repcat_setup NUMBER; 
  master_site number;
  masterdef number;
  mv_site number;
  mv_master number;
  detail varchar2(1000) := '';
BEGIN
  repcat_setup := 0;

  EXECUTE IMMEDIATE 'select count(*) from dba_repsites'
      INTO repcat_setup;

  IF repcat_setup = 0
  THEN
     RETURN c_success;
  ELSE
     master_site := 0;
     masterdef := 0;
     mv_site := 0;
     mv_master := 0;

     EXECUTE IMMEDIATE 'select count(*) from dba_repsites where dblink = ora_database_name and master = ''Y'' '
         INTO master_site;

     EXECUTE IMMEDIATE 'select count(*) from dba_repsites where dblink = ora_database_name and masterdef = ''Y'' '
         INTO masterdef;

     EXECUTE IMMEDIATE  'select count(*) from dba_repobject where type = ''MATERIALIZED VIEW'' '
         INTO mv_site;

     EXECUTE IMMEDIATE 'select count(*) from dba_repsites where dblink = ora_database_name and snapmaster = ''Y'' '
         INTO mv_master;

     IF masterdef > 0 THEN
         detail := detail ||
           '     o Master definition found.'||crlf||
           '       it is advised to remove all Master sites first.'||crlf||
           '       for more information look at section 7-31 of the '||crlf||
           '       Oracle Database Advanced Replication Management API Reference.';

     ELSIF master_site > 0 THEN
         detail := detail ||
           '     o Master site found.'||crlf||
           '       Steps to remove a Master site can be found' ||crlf||
           '       at section 7-31 of the Oracle Database Advanced Replication'
                   ||crlf||
           '       Management API Reference.';
     END IF;

     IF mv_master > 0 THEN
         detail := detail ||
           '     o Materialized View Master found.'
                 ||crlf||
           '       It is advised to remove all Materialized View sites first.'
                 ||crlf||
           '       for more information look at sections 8-1 to 8-10 of the'
                 ||crlf||
           '       Oracle Database Advanced Replication Management API Reference.';

     ELSIF mv_site > 0 THEN
         detail := detail ||
             '   o Materialized View site found.'
                   ||crlf||
             '     Steps to remove a MV site can be found'
                   ||crlf||
             '     at section 8-8 of the Oracle Database Advanced Replication'
                   ||crlf||
             '     Management API Reference.';
     END IF;

     result_txt := get_failed_check_xml('repcat_setup',
                     new string_array_t(),
                     'TEXT', detail);

     RETURN c_failure;
  END IF; 

  RETURN c_success;

 EXCEPTION WHEN OTHERS THEN  
   IF sqlcode = -942 THEN
     return c_success;
   END IF;
END repcat_setup_check;



-- *****************************************************************
--     OLS_VERSION_CHECK Section
-- This check verifies that the OLS version is same as CATPROC version
-- or is supported for direct upgrade. If not, the check alerts to the
-- user through an error.
-- *****************************************************************
FUNCTION ols_version_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
catproc_version    sys.registry$.version%type;
ols_version        sys.registry$.version%type;
ols_version_3_dots sys.v$instance.version%type;
BEGIN
-- Lrg 18421763: Check whether OLS is installed
IF dbms_registry.is_loaded('OLS') IS NOT NULL THEN
  SELECT version INTO catproc_version FROM sys.registry$ 
  WHERE cid = 'CATPROC';

  SELECT version INTO ols_version FROM sys.registry$
  WHERE cid = 'OLS';

  ols_version_3_dots :=
    dbms_registry_extended.convert_version_to_n_dots(ols_version, 3);

  IF ((ols_version = catproc_version) OR 
     (instr(',&C_UPGRADABLE_VERSIONS,',
            ',' || ols_version_3_dots || ',') != 0))
  THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('ols_version',
                    new string_array_t(), null, null);
    RETURN c_failure;
  END IF;
ELSE
  RETURN c_success;
END IF;
END ols_version_check;


-- *****************************************************************
--     AUDSYS.AUD$UNIFIED Section
-- *****************************************************************
-- Bug 24741114: Do not raise pre-upgrade error if audsys.aud$unified table's
-- partitions are not Oracle maintained.
FUNCTION UNIAUD_TAB_check (result_txt OUT VARCHAR2) RETURN number
IS
  tab_exists NUMBER := 1;
  t_null      CHAR(1);
  status      NUMBER;
BEGIN

  BEGIN
    EXECUTE IMMEDIATE
     'SELECT NULL FROM sys.obj$ o WHERE o.NAME = ''AUD$UNIFIED'' and ((o.namespace = 1 or o.type# = 2) and o.type# != 19) and o.owner# IN (select u.user# from sys.user$ u where u.name = ''AUDSYS'') and (bitand(o.flags, 4194304) != 4194304)'
      INTO t_null;
    EXCEPTION
      WHEN NO_DATA_FOUND then tab_exists := 0;
  END;

  IF (tab_exists = 0)
  THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('uniaud_tab',
                    new string_array_t(),
                    null, null);
    RETURN c_failure;
  END IF;
END UNIAUD_TAB_check;

-- ***********************************************************************
-- Bug 20950535 - HAVE PREUPGRD SCRIPT CHECK FOR MITIGATION PATCH 19721304 
-- This check verifies if javavm mitigation patch is installed and active 
-- in the DB.
-- ***********************************************************************
FUNCTION jvm_mitigation_patch_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null		CHAR(1);
BEGIN
    select null into t_null
    from sys.dba_triggers
    where trigger_name='DBMS_JAVA_DEV_TRG' and owner='SYS'
    and status='ENABLED';

    -- Java development is not allowed
	result_txt := get_failed_check_xml('jvm_mitigation_patch',
                      new string_array_t(db_version_4_dots,C_ORACLE_HIGH_VERSION_4_DOTS),
                     null, null);

    RETURN c_failure;
EXCEPTION
  WHEN NO_DATA_FOUND THEN RETURN c_success;
END jvm_mitigation_patch_check;

FUNCTION post_jvm_mitigat_patch_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null                CHAR(1);
BEGIN
    select null into t_null
    from sys.dba_triggers
    where trigger_name='DBMS_JAVA_DEV_TRG' and owner='SYS'
    and status='ENABLED';

    -- Java development is not allowed
        result_txt := get_failed_check_xml('post_jvm_mitigat_patch',
                      new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS),
                     null, null);

    RETURN c_failure;
EXCEPTION
  WHEN NO_DATA_FOUND THEN RETURN c_success;
END post_jvm_mitigat_patch_check;


--
-- Fixup javavm_mitigat_patch
--
FUNCTION jvm_mitigation_patch_fixup (
         result_txt IN OUT VARCHAR2,
         pSqlcode    IN OUT NUMBER) RETURN NUMBER
IS
    enable_java_dev_result BOOLEAN;
BEGIN
    enable_java_dev_result:= run_int_proc('SYS.DBMS_JAVA_DEV.ENABLE', result_txt, pSqlcode);

   IF (enable_java_dev_result) THEN
       RETURN c_success;
   ELSE
       RETURN c_failure;
   END IF;
END jvm_mitigation_patch_fixup;


-- *****************************************************************
--  AUDTAB_ENC_TS Section (Bug 23221566)
-- This check reminds user to remember to reopen the Oracle Encryption 
-- Wallet after the db has been opened in upgrade mode in the target 
-- Oracle home because some of the audit tables are stored into an
-- encrypted tablespace. Else db upgrade will abort.
-- *****************************************************************
FUNCTION AUDTAB_ENC_TS_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  aud_ts_encrypted NUMBER := 0;
  uniaud_ts_encrypted NUMBER := 0;
  wallet_open_status NUMBER := 0;
  uniaud_is_part NUMBER := 0;
  db_version     VARCHAR2(5);

BEGIN
  -- Get the current db version
  SELECT SUBSTR(version,1,4) INTO db_version FROM sys.registry$
  WHERE cid = 'CATPROC';

  IF db_version IN ('11.2') THEN
    -- Bug 23539027:Do not reference WALLET_TYPE column of V$ENCRYPTION_WALLET
    -- view as it does not exist in 11.2* DB vesrions
    -- Check if Oracle Encryption Wallet is Open
    EXECUTE IMMEDIATE 'SELECT count(*) FROM ' ||
    '(SELECT status, wrl_type FROM v$encryption_wallet ORDER BY ' ||
    ' wrl_type DESC) ks WHERE ROWNUM < 2 and ' ||
    'ks.status <> ''OPEN''' INTO wallet_open_status; 
  ELSE
    EXECUTE IMMEDIATE 'SELECT count(*) FROM v$encryption_wallet WHERE ' ||
    'status <> ''OPEN'' AND ' ||
    'wallet_type IN (''PRIMARY'', ''SINGLE'', ''UNKNOWN'')' INTO 
    wallet_open_status;
  END IF;

  IF (wallet_open_status > 0) THEN -- Wallet Not Open

    -- Check if AUD$/FGA_LOG$ is stored into an Encrypted Tablespace
    SELECT count(*) INTO aud_ts_encrypted FROM sys.ts$ t1, sys.tab$ t2
    WHERE (t1.ts# = t2.ts#)
    AND (bitand(t1.flags, 16384)=16384) -- encrypted tablespace bit check
    AND t2.obj# IN (SELECT o.obj# FROM sys.obj$ o WHERE
                    o.name IN ('AUD$', 'FGA_LOG$') AND (o.type# = 2)
                    AND o.owner# IN (SELECT u.user# FROM sys.user$ u
                    WHERE u.name IN ('SYS', 'SYSTEM') AND (u.type# = 1)));

    IF (aud_ts_encrypted > 0) THEN
      result_txt := get_failed_check_xml('audtab_enc_ts',
                                         new string_array_t(), null, null);
      return c_failure;
    END IF;

    -- Check if AUDSYS.AUD$UNIFIED is stored into an Encrypted Tablespace
    -- Before that, first check if AUDSYS.AUD$UNIFIED is Partitioned
    SELECT count(*) INTO uniaud_is_part FROM
    sys.partobj$ p, sys.obj$ o, sys.user$ u WHERE
    (p.obj# = o.obj#) AND (o.type# = 2) AND (o.name = 'AUD$UNIFIED') AND
    (o.owner# = u.user#) AND (u.name = 'AUDSYS') AND (u.type# = 1);

    IF (uniaud_is_part > 0) THEN  -- AUDSYS.AUD$UNIFIED is Partitioned
      SELECT count(*) INTO uniaud_ts_encrypted FROM
      sys.ts$ t1, sys.tabpart$ t2, sys.obj$ o, sys.user$ u
      WHERE (t1.ts# = t2.ts#) AND (bitand(t1.flags, 16384)=16384) AND
      (t2.bo# = o.obj#) AND (o.type# = 2) AND (o.name = 'AUD$UNIFIED') AND
      (o.owner# = u.user#) AND (u.name='AUDSYS') AND (u.type# = 1);
    ELSE
      SELECT count(*) INTO uniaud_ts_encrypted FROM
      sys.ts$ t1, sys.tab$ t2, sys.obj$ o, sys.user$ u
      WHERE (t1.ts# = t2.ts#) AND (bitand(t1.flags, 16384)=16384) AND
      (t2.obj# = o.obj#) AND (o.type# = 2) AND (o.name = 'AUD$UNIFIED')
      AND (o.owner# = u.user#) AND (u.name = 'AUDSYS') AND (u.type# = 1);
    END IF;

    IF (uniaud_ts_encrypted > 0) THEN
      result_txt := get_failed_check_xml('audtab_enc_ts',
                                         new string_array_t(), null, null);
      return c_failure;
    END IF;
  END IF;
  RETURN c_success;
EXCEPTION
  WHEN NO_DATA_FOUND THEN RETURN c_success;
END AUDTAB_ENC_TS_check;

-- *****************************************************************
--     TRGOWNER_NO_ADMNDBTRG Section
-- This check verifies whether there are database triggers created,
-- by users which didn't receive the privilege directly
-- *****************************************************************
FUNCTION trgowner_no_admndbtrg_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
    TRG_EXISTS     NUMBER := 0;
    TRGADM_QUERY   VARCHAR2(300) :='';
BEGIN
    TRGADM_QUERY:= 'SELECT COUNT(OWNER) TRG_EXISTS FROM DBA_TRIGGERS 
                    WHERE BASE_OBJECT_TYPE=''DATABASE'' AND 
                    OWNER NOT IN (SELECT GRANTEE FROM DBA_SYS_PRIVS 
                    WHERE PRIVILEGE=''ADMINISTER DATABASE TRIGGER'')';
    EXECUTE IMMEDIATE TRGADM_QUERY INTO TRG_EXISTS; 
    IF TRG_EXISTS = 0 THEN
        RETURN c_success;
    ELSE
        result_txt := get_failed_check_xml('trgowner_no_admndbtrg',
                    new string_array_t(),
                    null, null);
        RETURN c_failure;
    END IF;
END trgowner_no_admndbtrg_check;

-- *****************************************************************
--     XDB_RESOURCE_TYPE Section
-- This check verifies whether the attribute order of
-- XDB.XDB$RESOURCE_T is either correct or feasible for patch
-- *****************************************************************

FUNCTION xdb_resource_type_check (result_txt OUT VARCHAR2) RETURN NUMBER
 IS
   res_obj_cnt    number;
   res_attr_cnt   number;
   attr_no_RCL    number;
   attr_no_COBI   number;
   attr_no_BV     number;
   dep_tab_cnt    number;
   non_null_cnt   number;
   need_patch     boolean;
BEGIN
  select count(*) into res_obj_cnt from SYS.DBA_OBJECTS
  where  owner = 'XDB' and
         ((object_name = 'XDB$RESOURCE'   and object_type = 'TABLE') or
          (object_name = 'XDB$RESOURCE_T' and object_type = 'TYPE'));

  -- 22744959: XDB is not installed, and hence no wrong-ordered attributes
  if (res_obj_cnt <> 2) then
    return c_success;
  end if;

  select count(*) into res_attr_cnt from SYS.DBA_TYPE_ATTRS 
  where  owner = 'XDB' and type_name = 'XDB$RESOURCE_T' and
         attr_name in ('RCLIST', 'CHECKEDOUTBYID', 'BASEVERSION');

  -- 22744959: wrong-ordered attributes are not introduced yet
  if (res_attr_cnt = 0) then
    return c_success;

  elsif (res_attr_cnt = 3) then
    select attr_no into attr_no_RCL  from SYS.DBA_TYPE_ATTRS 
    where  owner = 'XDB' and type_name = 'XDB$RESOURCE_T' and
           attr_name = 'RCLIST';

    select attr_no into attr_no_COBI from SYS.DBA_TYPE_ATTRS
    where  owner = 'XDB' and type_name = 'XDB$RESOURCE_T' and
           attr_name = 'CHECKEDOUTBYID';

    select attr_no into attr_no_BV   from SYS.DBA_TYPE_ATTRS
    where  owner = 'XDB' and type_name = 'XDB$RESOURCE_T' and
           attr_name = 'BASEVERSION';

    select count(*) into dep_tab_cnt from SYS.DBA_DEPENDENCIES
    where referenced_owner = 'XDB' and referenced_name  = 'XDB$RESOURCE_T' and
          type = 'TABLE' and (owner != 'XDB' or name != 'XDB$RESOURCE');

    execute immediate
      'select count(*) from XDB.XDB$RESOURCE R
       where R.xmldata.checkedoutbyid is not null or
             R.xmldata.baseversion    is not null'
      into non_null_cnt;

    need_patch :=  (attr_no_RCL > attr_no_COBI) OR (attr_no_COBI > attr_no_BV);

    -- wrong-ordered attributes exist and can be repaired during upgrade
    if (not need_patch) or (dep_tab_cnt = 0 and non_null_cnt = 0) then
      return c_success;
    end if;

  end if;

  -- wrong-ordered attributes exist but beyond repair
  result_txt := get_failed_check_xml('xdb_resource_type',
                                     new string_array_t(), null, null);
  return c_failure;
END xdb_resource_type_check;

-- *****************************************************************
--     CASE_INSENSITIVE_AUTH Section
-- This check returns c_failure if the instance initialization parameter
-- SEC_CASE_SENSITIVE_LOGON has the value FALSE, meaning that the server
-- is configured to ignore the case of the password during authentication.
--
-- *****************************************************************
FUNCTION case_insensitive_auth_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  sec_case_sensitive_logon           number;
BEGIN
  --
  -- Get the value of the SEC_CASE_SENSITIVE_LOGON initialization parameter.
  --
  select decode (VALUE, 'FALSE', 0, 1) into sec_case_sensitive_logon
    from V$SYSTEM_PARAMETER
   where NAME='sec_case_sensitive_logon';

  if (sec_case_sensitive_logon = 1) then
    return c_success;
  end if;

  result_txt := get_failed_check_xml('case_insensitive_auth',
                                     new string_array_t(), null, null);
  return c_failure;
END case_insensitive_auth_check;

-- *****************************************************************
--     NETWORK_ACL_PRIV Section
-- This check looks for existing network ACLs in 11g to issue warnings
-- about a change in format in 12c.
-- *****************************************************************
FUNCTION network_acl_priv_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  net_acl_count    NUMBER := 0;
  wallet_acl_count NUMBER := 0;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE 'select count(*) from sys.net$_acl where rownum <= 1'
       INTO net_acl_count;
  EXCEPTION
    WHEN OTHERS THEN NULL;
  END;

  BEGIN
    EXECUTE IMMEDIATE 'select count(*) from sys.wallet$_acl where rownum <= 1'
       INTO wallet_acl_count;
  EXCEPTION
    WHEN OTHERS THEN NULL;
  END;

  IF (net_acl_count = 0 AND wallet_acl_count = 0)
  THEN
    RETURN c_success;
  END IF;

  result_txt := get_failed_check_xml('network_acl_priv',
                  new string_array_t(),
                  null, null);
  RETURN c_failure;

END network_acl_priv_check;

-- *****************************************************************
-- Bug 21289647 REMOTE_LOGIN_PASSWORDFILE parameter check
-- This check verifies that REMOTE_LOGIN_PASSWORDFILE is not SHARED
-- *****************************************************************
FUNCTION rlp_param_check (result_txt OUT VARCHAR2) RETURN number
IS
  is_rlp_shared    NUMBER := 0;
BEGIN

  BEGIN
    EXECUTE IMMEDIATE
     'SELECT 1 FROM sys.v$parameter WHERE upper(name) = ''REMOTE_LOGIN_PASSWORDFILE'' AND upper(value) = ''SHARED''' INTO is_rlp_shared;
  EXCEPTION
    WHEN OTHERS THEN NULL;
  END;

  IF (is_rlp_shared = 0)
  THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('rlp_param', new string_array_t(), null, null);
    RETURN c_failure;
  END IF;

END rlp_param_check;

-- *****************************************************************
-- Bug 22166873 - ADD PREUPGRADE CHECK FOR MATERIALIZED VIEWS REFRESH 
-- This check verifies all mv's are fresh and sumdelta$ is empty.
-- *****************************************************************
FUNCTION mv_refresh_check (result_txt OUT VARCHAR2) RETURN number
IS
  num_notfresh_mvs    NUMBER := 0;
  num_sumdelta_rows   NUMBER := 0;
BEGIN

  BEGIN
    EXECUTE IMMEDIATE
     'select count(*) from (select mview_name from all_mviews where staleness
      <> ''FRESH'')' into num_notfresh_mvs;
  EXCEPTION
    WHEN OTHERS THEN NULL;
  END;

  BEGIN
    EXECUTE IMMEDIATE
     'select count(*) from sys.sumdelta$' into num_sumdelta_rows;
  EXCEPTION
    WHEN OTHERS THEN NULL;
  END;

  IF (num_notfresh_mvs = 0 AND num_sumdelta_rows = 0)
  THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('mv_refresh', new string_array_t(), null, null);
    RETURN c_failure;
  END IF;

END mv_refresh_check;

-- ****************************************************************************
-- #(22454765) - ADD PREUPGRADE CHECK FOR METHOD_OPT preference of dbms_stats.
-- dbms_stats was not raising error properly when users set invalid value for 
-- this preference. For example, it was not raising error when user use FOR
-- COLUMNS clause when setting global prefernce. This is fixed in #(5917009).
-- However users were able to set the invalid value and it was causing errors
-- when gathering statistics during upgrade. This preupgrade check warns the
-- users during pre upgrade check if their database has wrong setting for this
-- preference. Currently it complains only if FOR COLUMNS clause is present
-- in the preference value.
-- ****************************************************************************
FUNCTION dbms_stats_method_opt_check (result_txt OUT VARCHAR2) RETURN number
IS
  pvalue    varchar2(32000);        -- global preference value
  valid     boolean;                -- is preference value valid?
BEGIN

  -- This script may run against db that does not have get_prefs function.
  -- So use old get_param function.
  pvalue := dbms_stats.get_param('METHOD_OPT');

  -- Check if global prefrence has FOR COLUMNS clause
  IF (pvalue is not null and regexp_like(pvalue, 'FOR[ ]+COLUMNS', 'i'))
  THEN
    valid := false;
  else
    valid := true;
  END IF;

  IF (valid)
  THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('dbms_stats_method_opt', 
                    new string_array_t(pvalue),
                    null, null);
    RETURN c_failure;
  END IF;

END dbms_stats_method_opt_check;


-- ***********************************************************************
-- Bug 22708956 - ADD INFORMATIONAL MESSAGES ABOUT DATA MININING OBJECTS
-- This check verifies the existance of data mining objects on customer TS
-- ***********************************************************************
FUNCTION data_mining_object_check    (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  t_null  CHAR(1);
BEGIN
    select null into t_null
        from modeltab$ m,  ts$ t, sys_objects s  
    where m.obj#=s.object_id
        and s.ts_number=t.ts#
        and t.name not in ('SYSTEM','SYSAUX')
        and rownum <=1;

    -- There are data mining objects in the database
  result_txt := get_failed_check_xml('data_mining_object',
                      new string_array_t(),
                      null, null);
  RETURN c_failure;
EXCEPTION
  WHEN NO_DATA_FOUND THEN RETURN c_success;
END data_mining_object_check;

-- *****************************************************************
--     PENDING_DST_SESSION Section
-- Bug 20669175 check for any pending dst session before upgrade
-- *****************************************************************
FUNCTION pending_dst_session_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
    DST_US_VALUE      VARCHAR2(4000) :='';
BEGIN
    EXECUTE IMMEDIATE 'SELECT property_value
                    FROM DATABASE_PROPERTIES
                    WHERE PROPERTY_NAME = ''DST_UPGRADE_STATE'''
    INTO DST_US_VALUE;

    IF DST_US_VALUE = 'NONE' THEN
        RETURN c_success;
    ELSE
        result_txt := get_failed_check_xml('pending_dst_session',
                    new string_array_t(DST_US_VALUE),
                    null, null);
        RETURN c_failure;
    END IF;
END pending_dst_session_check;

-- *****************************************************************
--     EXCLUSIVE_MODE_AUTH Section
-- This check returns c_failure if any account has only the 10G password
-- version (and neither the 11G nor the 12C password version).
--
-- The 10G password version is no longer accepted when the server
-- runs in Exclusive Mode, and starting with Oracle Database release 12.2
-- Exclusive Mode is the default password-based authentication mode,
-- so these accounts would become inaccessible
-- (an ORA-1017 "invalid username/password" error would be raised)
-- unless the customer relaxed the server's SQLNET.ORA setting for
-- the SQLNET.ALLOWED_LOGON_VERSION_SERVER parameter to a more
-- permissive setting (e.g. a value of 11). The default value for
-- the SQLNET.ALLOWED_LOGON_VERSION_SERVER parameter is 12 in Oracle
-- release 12.2.
--
-- In the DBA_USERS query, note the spaces within the
-- strings '10G ' and '10G HTTP ', and the use of the 
-- equality condition in the predicates.
--
-- The reason for including the PASSWORD_VERSIONS = '10G HTTP ' predicate
-- is that after the fix for 12.2 bug 22176897, the DBA_USERS view also
-- displays the presence of the HTTP password version (this password
-- version is unrelated to the O5LOGON protocol, it is only used by 
-- XDB for HTTP digest authentication).
--
--       select USERNAME, PASSWORD_VERSIONS
--         from DBA_USERS
--        where (PASSWORD_VERSIONS = '10G '
--           or  PASSWORD_VERSIONS = '10G HTTP ')
--          and (USERNAME <> 'ANONYMOUS');
--
-- Note that the ANONYMOUS user is excluded from the result set, as prior
-- to the fix for 12.2 bug 22176897 the ANONYMOUS user is reported by 
-- DBA_USERS as having a 10G password version. Also, AND has precedence
-- over OR, so parentheses are needed around the OR part of the predicate.
-- 
-- *****************************************************************
FUNCTION exclusive_mode_auth_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  only_10g_password_ver_present number;
BEGIN
  --
  -- Check if any account has only a 10G password version.
  --
  select count(*) into only_10g_password_ver_present
    from sys.dual                          
   where exists 
     (select 1
        from DBA_USERS
       where (PASSWORD_VERSIONS = '10G '
          or  PASSWORD_VERSIONS = '10G HTTP ')
         and (USERNAME <> 'ANONYMOUS'));

  if (only_10g_password_ver_present = 0) then
    return c_success;
  end if;

  result_txt := get_failed_check_xml('exclusive_mode_auth',
                                     new string_array_t(), null, null);
  return c_failure;
END exclusive_mode_auth_check;


-- *****************************************************************
--     min_archive_dest_size_check Section
--
-- Determine free space needed for when Archivelog is on and destination
-- is NOT in the recovery area
--
-- *****************************************************************

FUNCTION min_archive_dest_size_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  dest_name          VARCHAR2(256) := '';  -- e.g. LOG_ARCHIVE_DEST_1
  destination        VARCHAR2(256) := '';  -- path to archived logs
  continue_check     BOOLEAN := TRUE;  -- continue checking if alert is needed 
  check_stmt         VARCHAR2(1000);   -- check if alert is needed
  min_archivelog_gen INTEGER := 0;     -- min archive log bytes to be generated

BEGIN

  result_txt := '';

  destination        := archivedest_info.destination;
  dest_name          := archivedest_info.dest_name;
  min_archivelog_gen := archivedest_info.min_archive_gen;

  -- as an informational msg, let user know archiving is on
  -- and they need to ensure there is enough disk space to cover the amount
  -- of logs generated during the upgrade

  -- only generate a result string IF archive log size to be generated is > 0
  -- AND the archive log destination outside of fra is specified
  IF (min_archivelog_gen > 0)
     AND (dest_name IS NOT NULL)
  THEN
    result_txt :=
      get_failed_check_xml(
        'min_archive_dest_size',
        new string_array_t(destination,                        -- {1}
                           dest_name,                          -- {2}
                           displayBytes(min_archivelog_gen)),  -- {3}
        null, null);
    RETURN c_failure;
  ELSE
    RETURN c_success;
  END IF;

END min_archive_dest_size_check;


-- *****************************************************************
--     min_recovery_area_size_check Section
--
-- Determine minimum free space needed for when:
--  a) Archivelog is on
--  b) Flashback Database is on
--
-- *****************************************************************

FUNCTION min_recovery_area_size_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  db_recovery_modes  VARCHAR2(80)  := '';  -- archivelog, flashback
  db_recovery_logs   VARCHAR2(80)  := '';  -- archived logs, flashback logs

BEGIN

  IF db_log_mode = 'ARCHIVELOG' THEN
    db_recovery_modes := 'archivelog mode';
    IF is_archivelog_in_fra = TRUE THEN
      db_recovery_logs := 'archived logs';
    ELSE
      db_recovery_logs := '';
    END IF;
  END IF;

  IF db_flashback_on = TRUE THEN
    db_recovery_modes := 'archivelog and flashback';
    IF is_archivelog_in_fra = TRUE THEN
      db_recovery_logs  := 'archived and flashback logs';
    ELSE
      db_recovery_logs  := 'flashback logs';
    END IF;
  END IF;

  IF (fra_info.additional_size > 0) THEN
    result_txt :=
      get_failed_check_xml(
        'min_recovery_area_size',
        new string_array_t(db_recovery_modes,                    -- {1}
                           db_recovery_logs,                     -- {2}
                           fra_info.name,                        -- {3}
                           displayBytes(fra_info.limit),         -- {4}
                           displayBytes(fra_info.used),          -- {5}
                           displayBytes(fra_info.avail),         -- {6}
                           displayBytes(fra_info.min_fra_size)), -- {7}
        null, null);
    RETURN c_failure;
  ELSE
    RETURN c_success;
  END IF;
END min_recovery_area_size_check;

-- *****************************************************************
--     tempts_notempfile_check Section
-- Detects where the default temporary tablespace has no temp file
-- *****************************************************************
FUNCTION tempts_notempfile_check (result_txt OUT VARCHAR2) RETURN NUMBER
IS
  invtempts    VARCHAR2(50):='';
BEGIN
    BEGIN
      EXECUTE IMMEDIATE 'select TEMPORARY_TABLESPACE
                         from DBA_USERS
                         where upper(USERNAME)=''SYS''
                         and not exists (select 1 from DBA_TEMP_FILES a
                         where temporary_tablespace=a.TABLESPACE_NAME)'
      INTO invtempts;
     EXCEPTION WHEN NO_DATA_FOUND THEN RETURN c_success;
    END; 
    result_txt := get_failed_check_xml('tempts_notempfile',
                     new string_array_t(invtempts), null, null);
    return c_failure;
END tempts_notempfile_check;

--
--    ##NEW_CHECK## - add new *_check functions above here
--                    and optionally, the *_fixup function right after it.
--

BEGIN
  pDBGSizeResources := debug;

  check_level_ints( check_level_strings(c_check_level_success) ) := c_check_level_success;
  check_level_ints( check_level_strings(c_check_level_warning) ) := c_check_level_warning;
  check_level_ints( check_level_strings(c_check_level_info) ) := c_check_level_info;
  check_level_ints( check_level_strings(c_check_level_error) ) := c_check_level_error;
  check_level_ints( check_level_strings(c_check_level_recommend) ) := c_check_level_recommend;

  C_ORACLE_HIGH_VERSION_4_DOTS := '&C_ORACLE_HIGH_VERSION_4_DOTS';
  EXECUTE IMMEDIATE 'SELECT version FROM v$instance' INTO db_version_4_dots;
  db_version_3_dots := dbms_registry_extended.convert_version_to_n_dots(db_version_4_dots,3);
  db_version_2_dots := dbms_registry_extended.convert_version_to_n_dots(db_version_4_dots,2);
  db_version_1_dot  := dbms_registry_extended.convert_version_to_n_dots(db_version_4_dots,1);
  db_version_0_dots := dbms_registry_extended.convert_version_to_n_dots(db_version_4_dots,0);

  db_inplace_upgrade := (dbms_registry_extended.compare_versions(C_ORACLE_HIGH_VERSION_4_DOTS, db_version_4_dots, 3 ) = 0);

  EXECUTE IMMEDIATE 'SELECT name    FROM v$database' INTO db_name;
  EXECUTE IMMEDIATE 'SELECT dbms_preup.get_con_name FROM sys.dual' INTO con_name;
  EXECUTE IMMEDIATE 'SELECT dbms_preup.get_con_id FROM sys.dual' INTO con_id;

  EXECUTE IMMEDIATE 'SELECT value   FROM v$parameter WHERE name = ''compatible'''
     INTO db_compatible;

  EXECUTE IMMEDIATE 'SELECT value FROM v$parameter WHERE name = ''db_block_size'''
     INTO db_block_size;
  EXECUTE IMMEDIATE 'SELECT value FROM v$parameter WHERE name = ''undo_management'''
       INTO db_undo;
  EXECUTE IMMEDIATE 'SELECT value FROM v$parameter WHERE name = ''undo_tablespace'''
       INTO db_undo_tbs;
  EXECUTE IMMEDIATE 'SELECT value FROM sys.v$parameter WHERE name = ''cpu_count'''
        INTO param_as_string;
  db_cpus := to_number (param_as_string);
  EXECUTE IMMEDIATE
     'SELECT value FROM v$parameter WHERE name = ''parallel_threads_per_cpu'''
  INTO param_as_string;
  db_cpu_threads := pvalue_to_number(param_as_string);
  EXECUTE IMMEDIATE 'SELECT version from v$timezone_file'
    INTO db_tz_version;
  EXECUTE IMMEDIATE 'SELECT LOG_MODE from v$database'
     INTO db_log_mode;

  BEGIN
    db_is_XE := FALSE;
    EXECUTE IMMEDIATE
       'SELECT edition FROM sys.registry$ WHERE cid=''CATPROC'''
       INTO edition_str;
      IF edition_str = 'XE' THEN
         db_is_XE := TRUE;
      END IF; -- XE edition
  EXCEPTION
      WHEN OTHERS THEN
          NULL;
  END;

/***************************************************************************************
* Bug 23278082 - PREUPGRADE TOOL: PREUPGRADE_DRIVER.SQL ON 12.2.0.1 
*                DB: ORA-01403: NO DATA FOUND 
*
* The following query returns no rows in 12.2+, the solution is to add null management
* to the query, making it an anonymous procedure.
* 
****************************************************************************************/
  BEGIN
      EXECUTE IMMEDIATE 'SELECT value FROM v$parameter WHERE name = ''use_indirect_data_buffers'''
          INTO use_indirect_data_buffers;
      db_VLM_enabled := (use_indirect_data_buffers = 'TRUE');
  EXCEPTION
      WHEN NO_DATA_FOUND THEN
          db_VLM_enabled := FALSE;  -- As this is a boolean variable, the 'default value to be returned', 
                                    -- when the value does not exist or is false.
  END;

  EXECUTE IMMEDIATE 'SELECT open_mode FROM sys.v$database' INTO param_as_string;
  db_is_readonly := (SUBSTR(param_as_string, 1, 9) = 'READ ONLY');

/***************************************************************************************
* BUG 22124723: UPGRADE:THE NEW PREUPGRADE TOOL REPORT WRONG OPEN MODE OF PDB$SEED
*
* If PDB is SEED and due to the catcon or sqlplus approaches need to have the SEED in 
* read write mode, changing the logic to report as READ ONLY.
****************************************************************************************/

  IF (con_name like 'PDB%SEED') AND (NOT db_is_readonly) THEN
	db_is_readonly := TRUE;
  END IF;
  

  BEGIN
    EXECUTE IMMEDIATE 'select cdb from v$database' into cdb_string;
    db_is_cdb := (cdb_string = 'YES');
  EXCEPTION
    WHEN OTHERS THEN
      db_is_cdb := FALSE;
      cdb_constraint := '';
  END;

  IF db_is_cdb THEN
    cdb_constraint := ' AND origin_con_id IN (SELECT MAX(origin_con_id) FROM dba_directories ' ||
                      ' WHERE directory_name=''PREUPGRADE_DIR'' AND owner=''SYS'' AND ' ||
                      ' ((origin_con_id = 1) OR (origin_con_id = ' || to_char(con_id) || ')))';
  ELSE
    cdb_constraint := '';
  END IF;

  -- if this is a cdb, then query cdb/pdb info and assign to "global" variables
  IF db_is_cdb THEN
    db_n_pdbs  := sys.dbms_preup.get_npdbs;    -- # of pdbs as seen in v$pdbs
    db_is_root := sys.dbms_preup.is_con_root;  -- is container db ROOT? T/F
  ELSE
    db_n_pdbs  := 0;
    db_is_root := FALSE;
  END IF;
  IF debug_archive_fra = TRUE THEN
    dbms_output.put_line('ARCHIVE/FRA: in MAIN: db_n_pdbs ' || db_n_pdbs);
  END IF;

  BEGIN
    EXECUTE IMMEDIATE 'SELECT directory_path ' ||
                      '    FROM all_directories ' ||
                      '    WHERE owner=''SYS'' AND directory_name=''PREUPGRADE_DIR'' ' ||
                      cdb_constraint
                      INTO preupgrade_dir_path;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      dbms_output.put_line('ERROR - PREUPGRADE_DIR directory object must be defined.');
      RAISE;
  END;

  --
  -- Flashback on can have several 'on' states, but only one 'off' so check
  -- for NO.
  -- Put inside begin/end to catch execution on pre 10.x DB's where undo_tablespace
  -- is not defined yet.
  --
  BEGIN
    EXECUTE IMMEDIATE 'SELECT count(*) FROM v$database  WHERE flashback_on = ''NO'''
      INTO flashback_off;
    db_flashback_on := (flashback_off = 0);
    EXCEPTION
      WHEN OTHERS THEN
        db_flashback_on := TRUE;
  END;


  -- find out if fast recovery area (or FRA) is set
  -- note: answer is yes if init parameters db_recovery_file_dest_size
  -- and db_recovery_file_dest are set
  db_fra_set := FALSE;  -- initialize
  BEGIN
    BEGIN
      EXECUTE IMMEDIATE
        'SELECT count(*)
         FROM sys.v$parameter
         WHERE (name = ''db_recovery_file_dest'' AND value IS NOT NULL)'
      INTO tmp_number;
    EXCEPTION
      WHEN OTHERS THEN
        tmp_number := 0;
        dbms_output.put_line('ORA' || SQLCODE || ': Error in DBA_FRA_SET_a:');
        dbms_output.put_line(SQLERRM);
    END; 

    -- IF db_recovery_file_dest is set, then find out if
    -- db_recovery_file_dest_size is set.  If yes, then set db_fra_set to TRUE.
    IF tmp_number >= 1 THEN
      BEGIN
        EXECUTE IMMEDIATE
          'SELECT count(*)
           FROM sys.v$parameter
           WHERE (name = ''db_recovery_file_dest_size'' AND value <> ''0'')'
        INTO tmp_number;
      EXCEPTION
        WHEN OTHERS THEN
          tmp_number := 0;
          dbms_output.put_line('ORA' || SQLCODE || ': Error in DBA_FRA_SET_b:');
          dbms_output.put_line(SQLERRM);
      END; 
      IF tmp_number >= 1 THEN
        db_fra_set := TRUE;
      ELSE
        db_fra_set := FALSE;
      END IF;
    ELSE  -- tmp_number = 0
      db_fra_set := FALSE;
    END IF;

    IF debug_archive_fra = TRUE THEN
      IF db_fra_set = TRUE THEN
        dbms_output.put_line('ARCHIVE/FRA: fra set is TRUE');
      ELSIF db_Fra_set = FALSE THEN
        dbms_output.put_line('ARCHIVE/FRA: fra set is FALSE');
      ELSE
        dbms_output.put_line('ARCHIVE/FRA: fra set is BLANK');
      END IF;
    END IF;
  END;
    

  EXECUTE IMMEDIATE 'SELECT platform_id, platform_name
           FROM v$database'
  INTO db_platform_id, db_platform;
  IF db_platform_id NOT IN (1,7,10,15,16,17) THEN
    db_64bit := TRUE;
  ELSE
    db_64bit := FALSE;
  END IF;
  db_32bit := NOT db_64bit;

  --
  -- Set the newline depending on platform
  --
  IF INSTR(db_platform, 'WINDOWS') != 0 THEN
    crlf := CHR(13) || CHR(10);       -- Windows gets the \r and \n
  ELSE
    crlf := CHR (10);                 -- Just \n for the rest of the world
  END IF;

  BEGIN
      EXECUTE IMMEDIATE 
	'select substr(regexp_substr(banner, ''[^ ]+'', 1, 4),1,1) || 
	substr(regexp_substr(banner, ''[^ ]+'', 1, 5),1,1)
        from v$version
        where regexp_like(banner, ''Oracle Database.*'', ''i'')' 
       INTO db_edition;
  EXCEPTION
      WHEN OTHERS THEN
          db_edition := '';
  END;

  severity_names(C_CHECK_LEVEL_SUCCESS) :=   'SUCCESS';
  severity_names(C_CHECK_LEVEL_INFO) :=      'INFORMATION USEFUL';
  severity_names(C_CHECK_LEVEL_WARNING) :=   'DBA ACTION HIGHLY RECOMMENDED';
  severity_names(C_CHECK_LEVEL_ERROR) :=     'DBA ACTION REQUIRED';
  severity_names(C_CHECK_LEVEL_RECOMMEND) := 'DBA ACTION RECOMMENDED';

  invalid_xml_message.id := 'INVALID_XML';

  init_components();
  init_resources();
  init_parameters();

  --
  --    Find the properties file with all the CHECK properties
  --

  BEGIN
      props_file := utl_file.fopen('PREUPGRADE_DIR', 'preupgrade_messages.properties', 'r',32767);
      LOOP
          BEGIN
              utl_file.get_line(props_file, props_line);

              IF debug THEN
                  dbms_output.put_line('READ PROPERTY: ' || props_line);
              END IF;

              --
              --   Skip comments in the properties file, identified by
              --   blank lines or ones starting with #
              --
              IF (props_line IS NOT NULL) AND
                 (trim(substr(props_line,1, instr(props_line||'#','#')-1)) IS NOT NULL) THEN
                  equals_index := instr(props_line, '=');
                  property_name := upper(trim(substr(props_line, 1, equals_index-1)));
                  property_value := substr(props_line, equals_index + 1);
                  properties(property_name) := property_value;

                  --
                  --  Process entire property file, record each check in order.
                  --
                  IF (dbms_registry_extended.element(property_name,'.',1) = 'CHECK') THEN
                      check_name := dbms_registry_extended.element(property_name, '.', 2);
                      check_subproperty := dbms_registry_extended.element(property_name, '.', 3);
                      IF (upper(check_subproperty) = 'RULE') THEN
                          ordered_check_names(ordered_check_names.count + 1) := check_name;
                      END IF;
                  END IF;
              END IF;

          EXCEPTION WHEN no_data_found THEN
              utl_file.fclose(props_file);
              EXIT;
          END;
      END LOOP;
  EXCEPTION WHEN invalidFileOperation THEN
      dbms_output.put_line('ERROR - Cannot open the ' ||
          'preupgrade_messages.properties file from the directory object preupgrade_dir');
      RAISE;
  END;


  --
  --    For each CHECK gathered from the properties file,
  --    gather all of its associated properties and call DEFINE_CHECK
  --
  IF (ordered_check_names.count = 0) THEN
      dbms_output.put_line('ERROR - could not register any CHECKs to be run');
  ELSE
      FOR check_table_index IN 1 .. ordered_check_names.count LOOP
          check_name := ordered_check_names(check_table_index);

          --
          --    Process the property.
          --    Since properties will look like, CHECK.<checkname>.RULE=value
          --    and CHECK.<checkname>.BROKEN_RULE, whenever we hit a CHECK.<checkname>.RULE,
          --    go get the other properties, and call define_check.
          --
          BEGIN
              check_auto_fixup_available := 
                  (upper(properties('CHECK.' || check_name || '.AUTO_FIXUP_AVAILABLE')) = 'TRUE');
              define_check ( lower(check_name),
                             properties('CHECK.' || check_name || '.SEVERITY'),
                             properties('CHECK.' || check_name || '.RULE'),
                             properties('CHECK.' || check_name || '.BROKEN_RULE'),
                             properties('CHECK.' || check_name || '.ACTION'),
                             upper(properties('CHECK.' || check_name || '.FIXUP_STAGE')),
                             check_auto_fixup_available,
                             properties('CHECK.' || check_name || '.MIN_VERSION'),
                             properties('CHECK.' || check_name || '.MAX_VERSION') );
          EXCEPTION WHEN OTHERS THEN
              internal_error('invalid preupgrade_message.properties file format' ||
                             ' processing CHECK ' || check_name ||
                             ' The most likely cause is that the file is missing one of that CHECK''s ' ||
                             ' properties like .RULE, .BROKEN_RULE, etc.');
          END;

      END LOOP;
  END IF;

END dbms_preup;
/

show errors;
