MINI MINI MANI MO

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

Rem $Header: rdbms/admin/preupgrade_package.sql /st_rdbms_18.0/3 2018/08/02 08:17:20 raeburns Exp $
Rem
Rem preupgrade_package.sql
Rem
Rem Copyright (c) 2015, 2018, 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    BEGIN SQL_FILE_METADATA 
Rem    SQL_SOURCE_FILE: rdbms/admin/preupgrade_package.sql 
Rem    SQL_SHIPPED_FILE: rdbms/admin/preupgrade_package.sql 
Rem    SQL_PHASE: UTILITY
Rem    SQL_STARTUP_MODE: NORMAL 
Rem    SQL_IGNORABLE_ERRORS: NONE 
Rem    SQL_CALLING_FILE: rdbms/admin/preupgrade_driver.sql
Rem    END SQL_FILE_METADATA
Rem
Rem    MODIFIED   (MM/DD/YY)
Rem    apfwkr      06/27/18 - Backport raeburns_bug-27861452 from main
Rem    apfwkr      03/22/18 - Backport raeburns_bug-27523800 from main
Rem    bymotta     12/06/17 - BUG 27227129: BMMB Variable overflow fix
Rem    raeburns    04/15/18 - Bug 27861452: Add dir_symlinks_check and dir_symlinks_exist_check
Rem    raeburns    02/20/18 - Bug 27523800: remove dbms_registry_basic from
Rem                           preupgrade.jar
Rem    fvallin     11/01/17 - RTI 20726707: Added else statement
Rem                           to have None value in tbs_action in 
Rem                           tablespaces_check
Rem    fvallin     10/25/17 - Bug 26957831: Added condition in
Rem    ewittenb    10/18/17 - remove fixups for psuedo-check replacements
Rem    cmlim       10/10/17 - bug 25211082: bring in pdb_archivelog_kb from
Rem                           from 12.2.0.1 preupgrade_package.sql
Rem    ewittenb    09/28/17 - bug 26812429 - rolling upgrade needs
Rem                           _allow_compatibility_adv_w_grp
Rem    welin       09/21/17 - bug 26875355: Handle duplicate entries in 
Rem                           parameters.properties
Rem    jcarey      09/06/17 - Bug 26673741 - add olap_page_pool_size
Rem    ewittenb    08/15/17 - Request 26091010 - number the action items
Rem    cmlim       08/10/17 - bug 26394379: memory recommendations too high for
Rem                           CDBs
Rem    ewittenb    08/08/17 - Bug 26193656 invalid components display
Rem    ewittenb    08/08/17 - RTI-20492129 - postupgrade_fixups did not find
Rem                           18.0
Rem    frealvar    07/25/17 - Bug 26164053 change in exclusive_mode_auth
Rem    tojhuan     07/21/17 - Bug 25515456: remove check for SQLJ obj types
Rem    ewittenb    07/17/17 - update for 18.0
Rem    ewittenb    07/17/17 - update for 18.1
Rem    ewittenb    07/17/17 - bug-26193659 - tablespace info level
Rem    psolomon    07/06/17 - Bug 24923080: pga_aggregate_limit minimum check
Rem    raeburns    06/21/17 - Bug 26194017: Restore APEX check and messages
Rem    hvieyra     06/21/17 - Modify overlap_network_acl check to not use
Rem                           detail_type and detail_info parameters from
Rem                           function get_failed_check_xml
Rem    tojhuan     06/09/17 - Bug 24623721: preupgrade check for SQLJ obj types
Rem    cmlim       05/22/17 - bug 26024333: cap DB_CACHE_SIZE and
Rem                           LARGE_POOL_SIZE; add numa pool to memory sizing
Rem    hvieyra     05/15/17 - Fix for bug 25705134 - Tablespaces check to  
Rem                           properly manage success and failure cases.
Rem    fvallin     05/08/17 - Bug 25688882: Display undo total space counting
Rem                           local undo tablespace. Removed flashback_info check 
Rem                           as it is duplicated with min_recovery_area check 
Rem    fvallin     05/03/17 - Bug 24926629: Display information on default
Rem                           number of cycles if upgrading CDB
Rem    fvallin     04/18/17 - Bug 25912284: Changed prefix in lenght
Rem    frealvar    04/12/17 - Bug 25856232 change type of c_temp_minsz to avoid
Rem                           numeric overflows
Rem    risgupta    04/07/17 - Bug 25677837: Update DV simulation check as
Rem                           post upgrade
Rem    cmlim       04/06/17 - bug 24926629: create function to return default #
Rem                           pdbs upgrading in parallel
Rem    cmlim       04/02/17 - bug 25392096: size for minimum PROCESSES value
Rem                           needed for the db upgrade
Rem    ewittenb    03/30/17 - fix null comparison issue
Rem    cmlim       03/24/17 - bug 25423323: misc fixes:
Rem                           update audit_records_check,
Rem                           post_fixed_objects_check, db_cache_size.
Rem                           remove job_queue_process_check
Rem    bymotta     03/16/17 - Bug 24923249 - PRE-UPGRADE TOOL COULD NOT BE
Rem                           EXECUTED ON A READ ONLY PDB
Rem    ewittenb    03/16/17 - bug-25714511 - rollback segments check needs to
Rem                           confirm db_undo != auto
Rem    nrcorcor    03/16/17 - rti 20172688 - change parm
Rem                           _db_new_lost_write_protect to
Rem                           _db_shadow_lost_write_protect
Rem    frealvar    03/10/17 - Bug 25594468 false alert on tablespace auto extend
Rem    fvallin     03/09/17 - Bug 25339728: Added check to increase undo space
Rem                           in non cdb
Rem    frealvar    03/10/17 - Bug 24820083 Add a check to validate stats on
Rem                           fixed objects before upgrade.
Rem    ewittenb    03/08/17 - rti-20139647
Rem    raeburns    03/08/17 - Bug 25616909: Use UTILITY for SQL_PHASE
Rem    frealvar    03/05/17 - Create generic functions select_number, select_varchar2,
Rem                           select_has_rows.
Rem    frealvar    02/29/17 - Merge fit_to_terminal() and smart_pad()
Rem    frealvar    02/29/17 - Bug 25211930 tempts_notempfile check should
Rem                           also consider tablespace groups
Rem    fvallin     02/16/17 - Bug 25546400: Added current db_version_3_dots  when
Rem                           component info is not found 
Rem    welin       02/15/17 - Move obsolete params into a datafile
Rem    ewittenb    02/02/17 - fix line formatting issues
Rem    frealvar    01/25/17 - Bug 25045534 added more info to postfixup
Rem    risgupta    01/17/17 - Proj 67579: Add check whether DV simulation
Rem                           log has no records
Rem    ewittenb    01/09/17 - Project 71055/67762 New code to remap all of the
Rem                           <InitParams> and its sub-elements
Rem    welin       01/17/17 - format fix
Rem    frealvar    12/19/16 - Bug 25252028 remove check oracle_users_quota
Rem    frealvar    12/13/16 - Bug 24559392 removed extra new lines chars of 
Rem                           the preupgrade report generated 
Rem    frealvar    12/13/16 - Bug 24007257 check for quota of default users
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    ewittenb    12/01/16 - make component sizing and other data be table driven
Rem                           from components.properties.  Remove APEX from
Rem                           components upgraded by server upgrade.
Rem    raeburns    11/26/16 - Bug 25044977: add post-upgrade check for
Rem                           dependent tables
Rem                           Bug 25262869: add NOCYCLE to dependency$ query
Rem    raeburns    11/26/16 - Bug 23231337: remove automatic APEX upgrade
Rem    frealvar    11/18/16 - Fix wrong comment in code of removed params section
Rem    frealvar    11/15/16 - support for renamed tags max_version_exclusive and 
Rem    ealvarad    11/15/16 - RTI 19868924:_posting_ips removed
Rem    frealvar    11/15/16 - support por renamed tags max_version_exclusive and 
Rem                           min_version_inclusive and changed logic of comparison
Rem    frealvar    11/11/16 - Bug 25038937 fix missed tempfile issue in query
Rem    cmlim       10/30/16 - bug 24696626: remove pga_aggregate_limit
Rem                           recommendations
Rem                         - remove gather_schema_stats('SYS') from autofixup
Rem    frealvar    10/27/16 - LRG 19787764 increased max line length in xml
Rem    frealvar    10/15/16 - Bug 24762152 update obsolete/removed/deprecated
Rem                           parameters list
Rem    frealvar    10/15/16 - Bug 24695433 temp tablespace without temp file
Rem    bymotta     10/10/16 - Bug 24810548: Change label to Min Size For
Rem                           Upgrade
Rem    amunnoli    10/02/16 - Bug 24741114: do not error out for aud$unified
Rem                           table partitions
Rem    frealvar    09/30/16 - RTI 19787195 fix query that feeds all_parameters
Rem    frealvar    09/16/16 - RTI 19787818 data not found in all_parameters
Rem    hvieyra     09/07/16 - Bug 20950535. Check if JAVAVM mitigation
Rem                           patch is installed in the database.
Rem    frealvar    09/06/16 - Bug24479767 undescore deprecated/obsolete/removed params
Rem    frealvar    09/05/16 - Bug 23115292 adding new javavm preupgrade check
Rem    ewittenb    08/22/16 - XbranchMerge ewittenb_postup_12.2.0.1.0 from
Rem                           st_rdbms_12.2.0.1.0
Rem    cmlim       08/18/16 - bug 24448551: for now, do not recommend
Rem                           pga_aggregate_limit if value was default
Rem    bymotta     08/14/16 - XbranchMerge bymotta_bug_postfixup from
Rem                           st_rdbms_12.2.0.1.0
Rem    arvijaya    08/03/16 - Bug 24398111:exclude_seed_cdb_view obsolete 12201
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    08/01/16 - XbranchMerge ewittenb_postup from main
Rem    ewittenb    07/13/16 - bug 24340891 and 23641965 dbms_preup and preupgrade_dir must
Rem                           be present
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
set serverout on format wrapped

CREATE OR REPLACE PACKAGE dbms_preup AS

    c_build                  CONSTANT NUMBER := 1;    -- 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
    -- for 12.2 (and 18)
    C_MIN_FLASHBACK_KB_PER_PDB   CONSTANT NUMBER := 333 * 1024;

    -- sublist of users in 112 taken from catctl @ORACLEUSERSDATAFOR11
    orcl_usrs112 VARCHAR2(4000):= '''ANONYMOUS'',''APEX_040200'',
            ''APEX_PUBLIC_USER'',''APPQOSSYS'',
            ''AUDSYS'',''CTXSYS'',''DBHADOOP'',
            ''DBSNMP'',''DIP'',''DV_ACCTMGR'',
            ''DVF'',''DVSYS'',''EXFSYS'',
            ''FLOWS_FILES'',''GDS_CATALOG_SELECT'',
            ''GSMADMIN_INTERNAL'',''GSMCATUSER'',
            ''GSMUSER'',''LBACSYS'',''MDDATA'',
            ''MDSYS'',''OJVMSYS'',''OLAPSYS'',
            ''OPTIMIZER_PROCESSING_RATE'',
            ''ORACLE_OCM'',''ORDDATA'',
            ''ORDPLUGINS'',''ORDSYS'',
            ''OUTLN'',''PROVISIONER'',
            ''SI_INFORMTN_SCHEMA'',
            ''SPATIAL_CSW_ADMIN_USR'',
            ''SPATIAL_WFS_ADMIN_USR'',
            ''SYS'',''SYSBACKUP'',''SYSDG'',
            ''SYSKM'',''SYSTEM'',''TSMSYS'',
            ''WMSYS'',''XDB'',''XS$NULL'',
            ''XS_NSATTR_ADMIN''';

    --
    --    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(32767);
    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 CLOB
    );

    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           VARCHAR2(513), -- 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
    );

    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,
        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

    --
    --    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 CLOB;
    FUNCTION  xml_to_text(xml CLOB) RETURN CLOB;
    FUNCTION  run_fixup(check_name VARCHAR2) RETURN BOOLEAN;
    FUNCTION  run_fixup(check_name VARCHAR2, fixup_id NUMBER) RETURN BOOLEAN;
    PROCEDURE run_fixup_and_report (check_name VARCHAR2);  -- backwards compatibility
    FUNCTION  run_fixup_only(check_name IN VARCHAR2, check_result_xml IN OUT VARCHAR2) RETURN BOOLEAN;
    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;
    FUNCTION  run_int_proc (statement VARCHAR2, result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN BOOLEAN;
    FUNCTION  num_pdbs_upg_in_parallel RETURN NUMBER;
    FUNCTION  num_pdb_batches_upg (pdbs_in_parallel NUMBER) RETURN NUMBER;
    PROCEDURE find_processes_value;  -- find minimum processes value
    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 CLOB) RETURN BOOLEAN;

    FUNCTION oracle_reserved_users_check    (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION compatible_parameter_check     (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION ols_sys_move_check             (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION awr_dbids_present_check        (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION pa_profile_check               (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION em_present_check               (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION files_need_recovery_check      (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION files_backup_mode_check        (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION two_pc_txn_exist_check         (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION sync_standby_db_check          (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION ultrasearch_data_check         (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION remote_redo_check              (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION sys_default_tablespace_check   (result_txt OUT CLOB) 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 CLOB) RETURN NUMBER;
    FUNCTION depend_usr_tables_check        (result_txt OUT CLOB) 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 CLOB) RETURN NUMBER;
    FUNCTION invalid_sys_tabledata_check    (result_txt OUT CLOB) 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 CLOB) RETURN NUMBER;
    FUNCTION enabled_indexes_tbl_fixup      (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION ordimageindex_check            (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION invalid_objects_exist_check    (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION amd_exists_check               (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION exf_rul_exists_check           (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION new_time_zones_exist_check     (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION old_time_zones_exist_check     (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION dir_symlinks_check             (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION dir_symlinks_exist_check       (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION purge_recyclebin_check         (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION purge_recyclebin_fixup         (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION job_queue_process_0_check      (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION upg_by_std_upgrd_check         (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION xbrl_version_check             (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION apex_manual_upgrade_check         (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION default_resource_limit_check   (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION conc_res_mgr_check             (result_txt OUT CLOB) 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 CLOB) RETURN NUMBER;
    FUNCTION dictionary_stats_fixup         (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN number;
    FUNCTION hidden_params_check            (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION underscore_events_check        (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION audit_records_check            (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION post_fixed_objects_check       (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION post_dictionary_check          (result_txt OUT CLOB) 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 CLOB) RETURN NUMBER;
    FUNCTION overlap_network_acl_check      (result_txt OUT CLOB) RETURN number;
    FUNCTION repcat_setup_check             (result_txt OUT CLOB) RETURN number;
    FUNCTION ols_version_check              (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION uniaud_tab_check               (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION jvm_mitigation_patch_check     (result_txt OUT CLOB) 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 CLOB) RETURN NUMBER;
    FUNCTION audtab_enc_ts_check            (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION trgowner_no_admndbtrg_check    (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION xdb_resource_type_check        (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION network_acl_priv_check         (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION rlp_param_check                (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION mv_refresh_check               (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION dbms_stats_method_opt_check    (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION case_insensitive_auth_check    (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION exclusive_mode_auth_check      (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION data_mining_object_check       (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION pending_dst_session_check      (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION min_archive_dest_size_check    (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION min_recovery_area_size_check   (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION javavm_status_check            (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION tempts_notempfile_check        (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION pga_aggregate_limit_check      (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION dv_simulation_check            (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION parameter_min_val_check        (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION parameter_min_val_fixup        (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER;
    FUNCTION parameter_rename_check         (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION parameter_rename_fixup         (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER;
    FUNCTION parameter_new_name_val_check   (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION parameter_new_name_val_fixup   (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER;
    FUNCTION olap_page_pool_size_check       (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION parameter_obsolete_check       (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION parameter_obsolete_fixup       (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER;
    FUNCTION parameter_deprecated_check     (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION rollback_segments_check        (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION tablespaces_check              (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION tablespaces_info_check         (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION pre_fixed_objects_check        (result_txt OUT CLOB) RETURN NUMBER;
    FUNCTION pre_fixed_objects_fixup        (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER;
    FUNCTION cycle_number_check             (result_txt OUT CLOB) RETURN NUMBER;

    --
    --    ##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;


--
--    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),
                    fixup_is_detectable      BOOLEAN,
                    auto_fixup_available     BOOLEAN,
                    min_version_inclusive    VARCHAR2(20),
                    max_version_exclusive    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 hashtable_of_ints_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   NUMBER,       -- kbytes inuse in tablespace
  alloc   NUMBER,       -- kbytes allocated to tbs
  auto    NUMBER,       -- autoextend kbytes available
  avail   NUMBER,       -- total kbytes available
  delta   NUMBER,       -- kbytes required for upgrade
  inc_by  NUMBER,       -- kbytes to increase tablespace by
  min     NUMBER,       -- minimum required kbytes to perform upgrade
  addl    NUMBER,       -- 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    NUMBER, -- kbytes in use
  next     NUMBER, -- kbytes in NEXT
  max_ext  NUMBER, -- max extents
  auto     NUMBER  -- 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    hashtable_of_ints_t;
supported_component_index    hashtable_of_ints_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;
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;
con_name            VARCHAR2(128);
con_id              NUMBER;
cdb_constraint      VARCHAR2(1000);
preupgrade_dir_path VARCHAR2(600);
pga_limit_min_dbua  NUMBER;                     -- minimum pga_aggregate_limit value for DBUA xml file
high_version_apex   VARCHAR2(40) := '&C_APEX_VERSION_4_DOTS';

pMinFlashbackLogGen INTEGER;                    -- minimum flashbacklog setting
pminArchiveLogGen   INTEGER;                    -- minimum archivelog setting

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

--
--    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_count        NUMBER;                  -- tmp variable for count(*)

properties hash_map_t;
ordered_check_names string_array_collection_t;
invalid_xml_message message_t;
preupgradecheck_failure_count  NUMBER;

fixup_cols number_array_t := new number_array_t(0,-6, 2,C_MAX_CHECK_NAME_LENGTH, 2,10, 2,32);

-- ***********************************************************************
--                  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;

PROCEDURE internal_error(message clob)
IS
    prefix VARCHAR2(2000); 
    adjusted_message VARCHAR2(32767);
BEGIN
    --
    --    Preupgrade encountered an unexpected serious error
    --    that will prevent processing downstream.
    --    Emit message directly to output, now, just in case
    --    the exception mechanism gets sick too.
    --
    BEGIN
        prefix := properties('INTERNAL_ERROR');
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            -- can happen if the error precedes message initialization.
            prefix := ' ';
    END;

    IF length(message) + length(prefix) > 32600 THEN
        adjusted_message := substr(message,1, 32600) || ' (TRUNCATED)';
    ELSE
        adjusted_message := message;
    END IF;
    dbms_output.put_line(prefix || crlf || adjusted_message);

    EXECUTE IMMEDIATE 'BEGIN ' ||
                      ' RAISE_APPLICATION_ERROR (-20000, ''' || adjusted_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 CLOB, pad_width_incl_prefix NUMBER, prefix VARCHAR2) RETURN CLOB
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;

    IF prefix is NULL or length(prefix) = 0 THEN
        virtual_width := pad_width_incl_prefix;
    ELSE
        virtual_width := pad_width_incl_prefix - length(prefix);
    END IF;

    --
    --    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;


PROCEDURE format_long_output(outstr VARCHAR2)
IS
    next_line_start NUMBER := 1;
    next_crlf NUMBER := 1;  -- seed a non-zero dummy value
BEGIN
    WHILE next_crlf <> 0 LOOP
       next_crlf := instr(outstr, crlf, next_line_start);
       IF next_crlf <> 0 THEN
           dbms_output.put_line(substr(outstr, next_line_start, next_crlf - next_line_start));
           next_line_start := next_crlf + crlf_length;
       ELSE
           IF next_line_start < length(outstr) THEN
               dbms_output.put_line(substr(outstr, next_line_start));
           END IF;
       END IF;
    END LOOP;
END format_long_output;


--
-- Generic routines to handle no_data_found issues
--

FUNCTION select_varchar2(query VARCHAR2, no_data_found_value VARCHAR2) RETURN
VARCHAR2
IS
    result VARCHAR2(32767);
BEGIN
  BEGIN
    EXECUTE IMMEDIATE query into result;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      result := no_data_found_value;
    WHEN OTHERS THEN
      raise;
  END;
  RETURN result;
END select_varchar2;

FUNCTION select_number(query VARCHAR2, no_data_found_value NUMBER) RETURN
NUMBER
IS
    result NUMBER;
BEGIN
  BEGIN
    EXECUTE IMMEDIATE query into result;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      result := no_data_found_value;
    WHEN OTHERS THEN
      raise;
  END;
  RETURN result;
END select_number;

-- Returns true if a given query returns rows, false otherwise
FUNCTION select_has_rows(query VARCHAR2) RETURN BOOLEAN
IS
  t_null  CHAR(1);
BEGIN
  BEGIN
    EXECUTE IMMEDIATE query INTO t_null;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      RETURN FALSE;
    WHEN OTHERS THEN
      raise;
  END;
  RETURN TRUE;
END select_has_rows;

FUNCTION column_format(column_sizes number_array_t, column_values string_array_t) RETURN CLOB
IS
    column_num NUMBER;
    width NUMBER;
    align_left BOOLEAN;
    value CLOB;
    need_another_row BOOLEAN := true;
    subsequent_row string_array_t := column_values;
    result CLOB := '';

BEGIN
  subsequent_row := column_values;
  WHILE need_another_row LOOP
    need_another_row := false;
    FOR column_num IN 1 .. column_sizes.count LOOP
        width := column_sizes(column_num);
        value := subsequent_row(column_num);

        IF (value IS NULL) OR (width = 0) THEN
            -- do this case separately so we don't have unexpected string operations on nulls
            value := rpad(' ', abs(width));   -- doesn't matter if left/right align, even if width=0
        ELSE
            -- negative widths mean align output on the right (typical number format.)
            -- make width positive and determine which alignment we're using.
            align_left := (width > 0);
            width := abs(width);

            IF length(value) <= width THEN
                IF align_left THEN
                    value := rpad(value, width);    -- (align left = pad on right)
                ELSE
                    value := lpad(value, width);    -- (align right = pad on left)
                END IF;
                subsequent_row(column_num) := null;
            ELSE
                need_another_row := true;
                subsequent_row(column_num) := substr(value, width + 1);
                value := substr(value, 1, width);
            END IF;
        END IF;

        result := result || value;
    END LOOP;

    IF need_another_row THEN
        result := result || crlf;
    END IF;
  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 function returns TRUE if a component ID represents
--    a component that can be upgraded using the server upgrade software.
--
FUNCTION is_supported_component(cid VARCHAR2) RETURN BOOLEAN
IS
BEGIN
    return supported_component_index.exists(cid);
END is_supported_component;


--
--    This function returns TRUE if a component can be upgraded
--    by the server upgrade and is either present in the users db
--    or will be installed into the users db as part of the
--    server upgrade.  A "processed" component is one that
--    will be involved when the current DB is upgraded.
--
FUNCTION is_processed_component(cid VARCHAR2) RETURN BOOLEAN
IS
BEGIN
    IF is_supported_component(cid) THEN
        return cmp_info(supported_component_index(cid)).processed;
    ELSE
        return FALSE;
    END IF;
END is_processed_component;


--  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.
--    FILE IO limited to 32767 characters
PROCEDURE to_file(output_file UTL_FILE.FILE_TYPE, line IN VARCHAR2)
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 read_components_properties
IS
    props_file utl_file.file_type;
    props_line VARCHAR2(32767);
    property_name VARCHAR2(4000);
    property_value VARCHAR2(32767);
    version VARCHAR2(20);   -- holds the version read from the properties file
    component_id VARCHAR2(50);  -- holds the "CID" shorthand name for the component
    attribute_name VARCHAR2(50);  -- holds the name of a field of cmp_info
    new_index BINARY_INTEGER;
    equals_index NUMBER;
    first_dot_index NUMBER;
    second_dot_index NUMBER;
BEGIN
    props_file := utl_file.fopen('PREUPGRADE_DIR', 'components.properties', 'r',32767);
    LOOP
        BEGIN
            utl_file.get_line(props_file, props_line);
            IF debug THEN
                dbms_output.put_line('READ components.properties: ' || 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);
                --
                --    Now process the line we just read in.
                --    Its value is useful only if the version it
                --    pertains to matches the database version.
                --
                version := substr(property_name, 1, instr(property_name, '.', 1, 1) - 1);
                version := replace(version, '_', '.');    -- convert the underscores to the normal dots.
                --    version 18.0+ comparisons need to match only 1 dot, before that, we need 3.
                IF ( (dbms_registry_extended.compare_versions(db_version_1_dot, '18.0', 1) >= 0) AND
                     (dbms_registry_extended.compare_versions(db_version_1_dot, version, 1) = 0) ) OR
                   (dbms_registry_extended.compare_versions(db_version_3_dots, version, 3) = 0) THEN 
                    first_dot_index :=  instr(property_name, '.', 1, 1);
                    second_dot_index := instr(property_name, '.', 1, 2);
                    component_id :=   substr(property_name, first_dot_index+1, second_dot_index - first_dot_index - 1);
                    attribute_name := substr(property_name, second_dot_index+1);

                    IF supported_component_index.exists(component_id) THEN
                        new_index := supported_component_index(component_id);
                    ELSE 
                        new_index := cmp_info.count() + 1;
                        supported_component_index(component_id) := new_index;

                        --
                        --    Create blank entry for new component
                        --
                        --    These STATIC values will be filled in by
                        --    other attributes read from this file
                        --
                        cmp_info(new_index).cid := component_id;
                        cmp_info(new_index).cname := null;
                        cmp_info(new_index).script := null;
                        cmp_info(new_index).sys_kbytes := 0;
                        cmp_info(new_index).sysaux_kbytes := 0;
                        cmp_info(new_index).def_ts_kbytes := 0;
                        cmp_info(new_index).ins_sys_kbytes := 0;
                        cmp_info(new_index).ins_def_kbytes := 0;
                        cmp_info(new_index).archivelog_kbytes := 0;
                        cmp_info(new_index).flashbacklog_kbytes := 0;
                        --
                        --    These Dynamic values (dependent on DB)
                        --    will be computer later, outside this routine
                        --
                        cmp_info(new_index).version := null;
                        cmp_info(new_index).status := null;
                        cmp_info(new_index).schema := null;
                        cmp_info(new_index).def_ts := null;
                        cmp_info(new_index).processed := FALSE;
                        cmp_info(new_index).install := FALSE;

                    END IF;

                    IF (attribute_name = 'CNAME') THEN
                        cmp_info(new_index).cname := property_value;
                    ELSIF (attribute_name = 'SCRIPT') THEN
                        cmp_info(new_index).script := property_value;
                    ELSIF (attribute_name = 'SYS_KBYTES') THEN
                        cmp_info(new_index).sys_kbytes := to_number(property_value);
                    ELSIF (attribute_name = 'SYSAUX_KBYTES') THEN
                        cmp_info(new_index).sysaux_kbytes := to_number(property_value);
                    ELSIF (attribute_name = 'DEF_TS_KBYTES') THEN
                        cmp_info(new_index).def_ts_kbytes := to_number(property_value);
                    ELSIF (attribute_name = 'INS_SYS_KBYTES') THEN
                        cmp_info(new_index).ins_sys_kbytes := to_number(property_value);
                    ELSIF (attribute_name = 'INS_DEF_KBYTES') THEN
                        cmp_info(new_index).ins_def_kbytes := to_number(property_value);
                    ELSIF (attribute_name = 'ARCHIVELOG_KBYTES') THEN
                        cmp_info(new_index).archivelog_kbytes := to_number(property_value);
                    ELSIF (attribute_name = 'FLASHBACKLOG_KBYTES') THEN
                        cmp_info(new_index).flashbacklog_kbytes := to_number(property_value);
                    ELSIF (attribute_name = 'PDB_ARCHIVELOG_KBYTES') THEN
                        cmp_info(new_index).pdb_archivelog_kb := to_number(property_value);
                    ELSE
                        internal_error('Invalid components.properties line due to unknown attribute while processing: ' || props_line);
                    END IF;
                END IF;  -- no ELSE since this property pertains to a different release,

            END IF;  -- line had a valid name=value on it.

        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 ' ||
            'components.properties file from the directory object preupgrade_dir');
        RAISE;
    WHEN OTHERS THEN
        -- invalid components.xml file.
        internal_error('Invalid components.properties line processing: ' || props_line);
END read_components_properties;



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,
                         fixup_is_detectable  IN BOOLEAN,
                         min_version_inclusive     IN VARCHAR2,
                         max_version_exclusive     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).fixup_is_detectable := fixup_is_detectable;
    check_table(new_index).min_version_inclusive := min_version_inclusive;
    check_table(new_index).max_version_exclusive := max_version_exclusive;

    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.
    --  Comparing only one dot deep into the version number, regardless of C_ORACLE_HIGH_VERSION_4_DOTS
    IF dbms_registry_extended.compare_versions(db_version_1_dot, C_ORACLE_HIGH_VERSION_4_DOTS, 1) <> 0 THEN
      FOR i IN 1 .. cmp_info.count LOOP
        --
        -- 1. the "STATS" (aka MISC) component is a pseudo-component.
        --    it was created for computational convenience only.  Skip it from the XML.
        -- 2. catproc is handled as special part of catalog below.
        --
        IF (cmp_info(i).processed) AND NOT
           ((cmp_info(i).cid = 'STATS') OR
            (cmp_info(i).cid = 'CATPROC')) THEN
              --
              --    Treat CATALOG and CATPROC as one combined component
              --
              IF (cmp_info(i).cid = 'CATALOG') THEN
                IF ((cmp_info(i).status = 'VALID' OR
                     cmp_info(i).status = 'UPGRADED' ) AND
                    (cmp_info(supported_component_index('CATPROC')).status = 'VALID' OR
                     cmp_info(supported_component_index('CATPROC')).status = 'UPGRADED' )) THEN
                  status_attr := cmp_info(i).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 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;


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 db_log_mode = 'ARCHIVELOG' THEN
      resourcenum := pMinArchiveLogGen / c_kb;
    ELSE
      resourcenum := 0;
    END IF;
    result := result || '  <ArchiveLogs name="ArchiveLogs" additional_size="' ||
                                      resourcenum || '" />' || crlf;

    IF db_flashback_on THEN
      resourcenum := pMinFlashbackLogGen / c_kb;
    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;

    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;
    return_string VARCHAR2(4000);
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) ||
                   '" type="NUMBER"/>' || 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(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;

    -- special case "pga_aggregate_limit"
    IF pga_aggregate_limit_check(return_string) <> c_success THEN
      --
      -- Display the minimum pga_aggregate_limit value 
      --
      result := result || '  <Parameter name="pga_aggregate_limit" atleast="' ||
                to_char(pga_limit_min_dbua) || '" type="NUMBER"/>' || 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 CLOB,
                           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 CLOB,
                      start_index IN NUMBER,
                      end_index IN NUMBER) RETURN CLOB
IS
    body_start_index NUMBER;
    body_end_index NUMBER;
    result CLOB;
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 CLOB,
                               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 CLOB,
                          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 CLOB,
                          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 CLOB,
                               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 CLOB,
                               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 CLOB
IS
    result CLOB;
    this_messagevalue messagevalue_t;
    standard_replacement_count NUMBER; -- number of replacements that precede any <Tableout if present.

    tableout_index NUMBER;             -- Index of "<Tableout" in message, 0 if not present
    tableout_suffix VARCHAR2(4000);    -- Message text that appears AFTER a <Tableout> tag.
    start_index NUMBER;                -- Index of "startParam=" clause in message containing <Tableout
    columns_index NUMBER;              -- Index of "columns=" clause in message containing <Tableout
    end_columns_index NUMBER;          -- Ending index of the columns= clause, if present
    starting_parameter_number NUMBER;  -- Value of the "<Tableout startParam=" clause
    column_size_array number_array_t;  -- Array of column widths - built for call to column_format()
    total_columns NUMBER := 0;
    columns_string VARCHAR2(200);      -- Value of "<Tableout columns=" clause
    column_width_string VARCHAR2(20);  -- String holding parsed value of a single column width from "<Tableout columns="
    column_width NUMBER;               -- numeric value of column_width_string
    rows PLS_INTEGER;                  -- count of rows that will appear in table.  No decimals
    real_cols_per_row PLS_INTEGER;     -- since each column value is padded with a virtual column of spaces, its 2 cols to a "real" col.  No decimals.
    row NUMBER;
    col NUMBER;
    i NUMBER;
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;


    standard_replacement_count := message.messagevalues.count;

    --
    --    See if there are any <Tableout> tags in the message and if so, prepare for them.
    --
    tableout_index := instr(result, '<Tableout', 1, 1);
    IF tableout_index > 0 THEN
        start_index := instr(result, 'startParam=', tableout_index, 1);
        columns_index := instr(result, 'columns=', start_index, 1);
        end_columns_index := instr(result, '>', columns_index, 1);

        IF debug THEN
            dbms_output.put_line(' ');
            dbms_output.put_line(message.id);
            dbms_output.put_line('start_index=' || to_char(start_index));
            dbms_output.put_line('columns_index=' || to_char(columns_index));
            dbms_output.put_line('end_columns_index=' || to_char(end_columns_index));
        END IF;

        IF (start_index = 0) or
           (columns_index = 0) or 
           (end_columns_index = 0) THEN
            internal_error('Invalid <Tableout> tag in preupgrade_messages.properties processing ' || message.id);
        END IF;

        BEGIN
            starting_parameter_number := to_number(substr(result,start_index+11,columns_index-start_index-11));
            standard_replacement_count := starting_parameter_number - 1;

            columns_string := substr(result, columns_index+8, end_columns_index-columns_index-8);
            
            column_width_string := dbms_registry_extended.element(columns_string, ',', total_columns + 1);
            column_size_array := new number_array_t();
            WHILE (column_width_string <> ',') LOOP
                column_width := to_number(column_width_string);

                column_size_array.extend();
                total_columns := total_columns + 1;
                column_size_array(total_columns) := column_width;

                column_width_string := dbms_registry_extended.element(columns_string, ',', total_columns + 1);
            END LOOP;

        EXCEPTION WHEN OTHERS THEN
            internal_error('in message_t_to_text, could not parse Tableout string in message.id=' || message.id);
        END;
    END IF;

    IF debug THEN
        dbms_output.put_line('in message_t_to_text, ' ||
            'total replacements=' || to_char(message.messagevalues.count));
    END IF;

    --
    --    Now loop through the messagevalues and perform replacements
    --    Note that this process may invalidate tableout_index, start_index,
    --    columns_index, and end_columns_index but they will be recomputed later.
    --
    FOR replacement IN 1 .. standard_replacement_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 Tableout replacements
    --
    IF (tableout_index > 0) THEN
        --
        --    REcompute the indexes of the pieces of the <Tableout> tag.
        --    the indexes could have been altered by the standard substitution process.
        --
        tableout_index := instr(result, '<Tableout', 1, 1);
        start_index := instr(result, 'startParam=', tableout_index, 1);
        columns_index := instr(result, 'columns=', start_index, 1);
        end_columns_index := instr(result, '>', columns_index, 1);

        -- chop off the <Tableout ...> content from result temporarily to make subsequent string operations easy
        tableout_suffix := substr(result, end_columns_index + 1);
        result := substr(result,1,tableout_index - 1);

        real_cols_per_row := column_size_array.count() / 2;
        rows := (message.messagevalues.count - standard_replacement_count) / real_cols_per_row;

        IF (standard_replacement_count + rows * real_cols_per_row != message.messagevalues.count) THEN
            IF debug THEN
                FOR i in 1..message.messagevalues.count LOOP
                    dbms_output.put_line(message.messagevalues(i).value);
                END LOOP;
            END IF;
            internal_error('called message_t_to_text() for message ' || message.id ||
             ' with invalid parameter count.' || crlf ||
             ' processing <Tableout ' || crlf ||
             ' messagevalues.count=' || to_char(message.messagevalues.count) || crlf ||
             ' expecting ' || to_char(standard_replacement_count + rows * real_cols_per_row) || crlf ||
             ' standard_replacement_count=' || to_char(standard_replacement_count) || crlf ||
             ' rows=' || to_char(rows) || crlf ||
             ' real_cols_per_row=' || to_char(real_cols_per_row));
        END IF;

        FOR row IN 1..rows LOOP
            DECLARE
                -- declare here to ensure it starts clean for every row
                column_format_array string_array_t := string_array_t();
            BEGIN
                FOR col IN 1..real_cols_per_row LOOP
                    column_format_array.extend(2);
                    column_format_array(col * 2 - 1) := ' ';
                    column_format_array(col * 2    ) := message.messagevalues(standard_replacement_count + (row-1)*real_cols_per_row + col).value;

                END LOOP;

                IF (row > 1) THEN
                    -- need crlf before all table output except the first line.
                    result := result || crlf;
                END IF;

                result := result || column_format(column_size_array, column_format_array);
            END;
        END LOOP;

        -- put back any suffix that was temporarily removed
        result := result || tableout_suffix;
    END IF;

    --
    --  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 CLOB,
                                  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 CLOB,
                                   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 CLOB,
                                   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 CLOB,
                                   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 CLOB,
                              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 CLOB,
                               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 CLOB,
                                 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 CLOB,
                                 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 CLOB,
                                 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', '', start_index);
    result.used := get_xml_attribute(xml, 'used', '', start_index);
    result.dsize := get_xml_attribute(xml, 'size', '', start_index);
    result.reclaimable := get_xml_attribute(xml, 'reclaimable', '', start_index);
    result.files := get_xml_attribute(xml, 'files', '', start_index);
    result.min_fra_size := get_xml_attribute(xml, 'min_fra_size', '', start_index);

    RETURN result;
END parse_flashback_info_xml;


FUNCTION parse_systemresource_xml(xml IN CLOB,
                                  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);
            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 CLOB,
                                 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 CLOB,
                                   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 CLOB,
                                   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 CLOB,
                                   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 CLOB,
                                   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
    now VARCHAR2(60);
BEGIN
    -- do not print out xmlns or upgradable_versions
    EXECUTE IMMEDIATE 'select to_char(sysdate, ''YYYY-MM-DD"T"HH24:MI:SS'') from dual'
        INTO now;
    -- use locale default format - no, java defaults differ from plsql.
    -- EXECUTE IMMEDIATE 'select to_char(to_timestamp(sysdate)) from dual' INTO now;
    RETURN 'Report generated by Oracle Database Pre-Upgrade Information Tool Version ' ||
           rdbmsup.version || ' on ' || now || crlf ||
           crlf ||
           'Upgrade-To version: ' || rdbmsup.version || crlf ||
           crlf ||
           '=======================================' || crlf ||
           'Status of the database prior to upgrade' || crlf ||
           '=======================================' || 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 || crlf || crlf;
END database_t_to_text;

FUNCTION preupgradecheck_t_to_text(preupgradecheck preupgradecheck_t) RETURN CLOB
IS
    auto_fixup_text VARCHAR2(100);
    result CLOB;
    indent_width NUMBER := 6;
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;

    preupgradecheck_failure_count := preupgradecheck_failure_count + 1;

    IF preupgradecheck.fixup.fixup_type = 'AUTOMATIC' THEN
        auto_fixup_text := C_FIXUP_TAG || ' ';
    ELSE
        auto_fixup_text := '';
    END IF;

    result := smart_pad(auto_fixup_text ||
                        message_t_to_text(preupgradecheck.action) || crlf || crlf ||
                        message_t_to_text(preupgradecheck.broken_rule) || crlf || crlf ||
                        message_t_to_text(preupgradecheck.rule),
                        C_TERMINAL_WIDTH, rpad(' ', indent_width, ' '));
    result := '  ' || substr(to_char(preupgradecheck_failure_count) || '.   ', 1, 4) || substr(result,indent_width+1);
    RETURN result;

END preupgradecheck_t_to_text;



FUNCTION autofixup_message(is_pre_fixup boolean) RETURN VARCHAR2
IS
    result VARCHAR2(4000);
    script_line VARCHAR2(600);
    fixup_script_name VARCHAR2(100);
    before_or_after VARCHAR2(10);
    container_expr VARCHAR2(150);
    container_expr2 VARCHAR2(40);
BEGIN
    IF is_pre_fixup THEN
        fixup_script_name := C_FIXUP_SCRIPT_NAME_PRE_BASE;
        before_or_after := 'BEFORE';
    ELSE
        fixup_script_name := C_FIXUP_SCRIPT_NAME_POST_BASE;
        before_or_after := 'AFTER';
    END IF;

    IF db_is_cdb THEN
        container_expr := ' container ' || con_name;
        container_expr2 := ' from within the container';
    ELSE
        container_expr := '';
        container_expr2 := '';
    END IF;

    result := '  ORACLE GENERATED FIXUP SCRIPT' || crlf ||
              '  =============================' || crlf ||
              '  All of the issues in database ' || db_name || container_expr || crlf ||
              '  which are identified above as ' || before_or_after || ' UPGRADE "(AUTOFIXUP)" can be resolved by' || crlf ||
              '  executing the following' || container_expr2 || crlf ||
              crlf;

    script_line := 'SQL>@' || preupgrade_dir_path || dir_sep || fixup_script_name || '.sql';

    return result || smart_pad(script_line, C_TERMINAL_WIDTH, '    ') || crlf || crlf;
END autofixup_message;


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;
    autofixups_available BOOLEAN := false;
BEGIN
    last_index := preupgradechecks.count;

    --
    --    Reset this to 0.  preupgradecheck_t_to_text will walk through them and increment this each time.
    --
    preupgradecheck_failure_count := 0; 

    result := '==============' || crlf ||
              'BEFORE UPGRADE' || crlf ||
              '==============' || crlf ||
              crlf ||
              '  REQUIRED ACTIONS' || crlf ||
              '  ================' || crlf;

    --
    --    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;
        autofixups_available := autofixups_available OR
                                (preupgradechecks(check_index).fixup.fixup_type = 'AUTOMATIC');
        check_index := check_index + 1;
    END LOOP;

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

    --
    --    RECOMMENDED ACTIONS - the header is displayed only if needed.
    --
    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_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;
        autofixups_available := autofixups_available OR
                                (preupgradechecks(check_index).fixup.fixup_type = 'AUTOMATIC');
        check_index := check_index + 1;
    END LOOP;


    --
    --    INFORMATION ONLY
    --
    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;
        autofixups_available := autofixups_available OR
                                (preupgradechecks(check_index).fixup.fixup_type = 'AUTOMATIC');
        check_index := check_index + 1;
    END LOOP;

    IF autofixups_available THEN
        result := result || autofixup_message(true);
    END IF;

    displayed_header := false;
    autofixups_available := false;  -- reset for the AFTER upgrade fixups.

    result := result ||
              '=============' || crlf ||
              'AFTER UPGRADE' || crlf ||
              '=============' || 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;
        autofixups_available := autofixups_available OR
                                (preupgradechecks(check_index).fixup.fixup_type = 'AUTOMATIC');
        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;
        autofixups_available := autofixups_available OR
                                (preupgradechecks(check_index).fixup.fixup_type = 'AUTOMATIC');
        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;
        autofixups_available := autofixups_available OR
                                (preupgradechecks(check_index).fixup.fixup_type = 'AUTOMATIC');
        check_index := check_index + 1;
    END LOOP;

    IF autofixups_available THEN
        result := result || autofixup_message(false);
    END IF;

    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 components_t_to_text(components components_t) RETURN VARCHAR2
IS
    result VARCHAR2(4000);
    ui VARCHAR2(17);
    invalid_components BOOLEAN := FALSE;
    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;

            IF comp.status = 'INVALID' THEN
                invalid_components := TRUE;
            END IF;

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

    IF invalid_components and db_is_cdb THEN
        result := result || crlf ||
                  '  There are INVALID components.  Please attempt to recompile INVALID components' || crlf ||
                  '  from $ORACLE_HOME/rdbms/admin.  For example, :' || crlf ||
                  crlf ||
                  '    $ORACLE_HOME/perl/bin/perl catcon.pl -n 1 -e -b utlrp -d ''''''.'''''' utlrp.sql' || crlf ||
                  crlf ||
                  '  (For the best performance, you may want to set the -n value to suit your system.)' || crlf ||
                  '  Then, run the preupgrade.jar again.' || crlf;
    END IF;

    RETURN result || crlf;
END components_t_to_text;


FUNCTION tablespaces_t_to_text(tablespaces tablespaces_t) RETURN CLOB
IS
BEGIN
    RETURN '';
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
BEGIN
    RETURN '';
END rollback_segments_t_to_text;


FUNCTION flashback_info_t_to_text(flashback_info flashback_info_t) RETURN CLOB
IS
BEGIN
    RETURN '';
END flashback_info_t_to_text;


FUNCTION systemresource_t_to_text(systemresource systemresource_t) RETURN CLOB
IS 
BEGIN
    RETURN '';
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
    RETURN '';
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.
        -- 

        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 CLOB
IS
    my_check check_record_t;
    broken_rule CLOB;
    action CLOB;
    idx NUMBER;
    fixup_type CLOB;
    messageValues CLOB := '';
    escapedOutput CLOB;
    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 (username IN VARCHAR2,
                            first_version_reserved IN VARCHAR2)
                            RETURN VARCHAR2
IS
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: version check starting: db_version=' ||
                             db_version_4_dots);
        dbms_output.put_line('in get_reserved_user: version check starting: reserved  =' ||
                             first_version_reserved);
        dbms_output.put_line('in get_reserved_user: version check starting: high vers =' ||
                             C_ORACLE_HIGH_VERSION_4_DOTS);
        dbms_output.put_line('in get_reserved_user: 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: 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, version checked, user must not exist in db');
        END IF;

        IF select_has_rows('SELECT null from SYS.USER$ WHERE name='''||username||'''') THEN
            RETURN '<br>' || username;
        END IF;
    END IF;

    RETURN '';

END get_reserved_user;



--
--    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_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 := TRUE;');
    IF (PRE_or_POST = 'PRE') THEN
      to_file(fixup_script, '  recyclebin_cleaned BOOLEAN := TRUE;');
      to_file(fixup_script, '  check_result_xml VARCHAR2(32767);');
    END IF;
    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('' '');');
    ELSE
        to_file(fixup_script, '  -- Starting DB ' || db_name);
    END IF;

    to_file(fixup_script, ' ');
    to_file(fixup_script, '    dbms_output.put_line(''Preup                             Preupgrade                    '');');
    to_file(fixup_script, '    dbms_output.put_line(''Action                            Issue Is                      '');');
    to_file(fixup_script, '    dbms_output.put_line(''Number  Preupgrade Check Name     Remedied    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
    -- Footer message
    IF PRE_or_POST = 'PRE' THEN
      to_file(fixup_script, ' ');
      to_file(fixup_script, '    --');
      to_file(fixup_script, '    -- clean recyclebin in case any of the above fixups left stuff there.');
      to_file(fixup_script, '    --');
      to_file(fixup_script, '    recyclebin_cleaned := dbms_preup.run_fixup_only(''purge_recyclebin'', check_result_xml);');
      to_file(fixup_script, ' ');
      to_file(fixup_script, '    IF fixup_result = FALSE THEN');
      to_file(fixup_script, '       dbms_output.put_line('''');');
      to_file(fixup_script, '       dbms_output.put_line(''The fixup scripts have been run and resolved what they can. However,'');');
      to_file(fixup_script, '       dbms_output.put_line(''there are still issues originally identified by the preupgrade that'');');
      to_file(fixup_script, '       dbms_output.put_line(''have not been remedied and are still present in the database.'');');
      to_file(fixup_script, '       dbms_output.put_line(''Depending on the severity of the specific issue, and the nature of'');');
      to_file(fixup_script, '       dbms_output.put_line(''the issue itself, that could mean that your database is not ready'');');
      to_file(fixup_script, '       dbms_output.put_line(''for upgrade.  To resolve the outstanding issues, start by reviewing'');');
      to_file(fixup_script, '       dbms_output.put_line(''the preupgrade_fixups.sql and searching it for the name of'');');
      to_file(fixup_script, '       dbms_output.put_line(''the failed CHECK NAME or Preupgrade Action Number listed above.'');');
      to_file(fixup_script, '       dbms_output.put_line(''There you will find the original corresponding diagnostic message'');');
      to_file(fixup_script, '       dbms_output.put_line(''from the preupgrade which explains in more detail what still needs'');');
      to_file(fixup_script, '       dbms_output.put_line(''to be done.'');');
      to_file(fixup_script, '    END IF;');
    ELSE
      to_file(fixup_script, '    IF fixup_result = FALSE THEN');
      to_file(fixup_script, '       dbms_output.put_line('''');');
      to_file(fixup_script, '       dbms_output.put_line(''The fixup scripts have been run and resovled what they can. However,'');');
      to_file(fixup_script, '       dbms_output.put_line(''there are still issues originally identified by the preupgrade that'');');
      to_file(fixup_script, '       dbms_output.put_line(''have not been remedied and are still present in the database.'');');
      to_file(fixup_script, '       dbms_output.put_line(''Depending on the severity of the specific issue, and the nature of'');');
      to_file(fixup_script, '       dbms_output.put_line(''the issue itself, that could mean that your database upgrade is not'');');
      to_file(fixup_script, '       dbms_output.put_line(''fully complete.  To resolve the outstanding issues, start by reviewing'');');
      to_file(fixup_script, '       dbms_output.put_line(''the postupgrade_fixups.sql and searching it for the name of'');');
      to_file(fixup_script, '       dbms_output.put_line(''the failed CHECK NAME or Preupgrade Action Number listed above.'');');
      to_file(fixup_script, '       dbms_output.put_line(''There you will find the original corresponding diagnostic message'');');
      to_file(fixup_script, '       dbms_output.put_line(''from the preupgrade which explains in more detail what still needs'');');
      to_file(fixup_script, '       dbms_output.put_line(''to be done.'');');
      to_file(fixup_script, '    END IF;');
    END IF;

    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;


--
--    This API to run_fixup(check_name) is provided for backward
--    compatibility.  It will set the fixup_id = 0 for all fixups.
--    that will work just fine, but the output will not number
--    the fixups.
--
FUNCTION run_fixup(check_name VARCHAR2) RETURN BOOLEAN
IS
BEGIN
    return run_fixup(check_name, 0);
END run_fixup;



FUNCTION run_fixup(check_name VARCHAR2, fixup_id NUMBER) RETURN BOOLEAN
IS
    this_check check_record_t;
    check_is_success BOOLEAN;
    fixup_is_success BOOLEAN;
    problem_remedied BOOLEAN;
    check_result_xml VARCHAR2(32767);
    original_message VARCHAR2(32767);
    dba_action       VARCHAR2(400);
    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.
    --
    this_check := get_check_record_by_name(check_name);
    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
        -- state 1: problem previously fixed.
        problem_remedied := true;
        dba_action := 'None.';
    ELSE
        IF (NOT this_check.auto_fixup_available) THEN
            -- state 2: problem still present, but no auto-fixup routine available.
            problem_remedied := false;
            IF (this_check.severity = C_CHECK_LEVEL_ERROR) THEN
                dba_action := 'Manual fixup required.';
            ELSIF (this_check.severity = C_CHECK_LEVEL_WARNING) THEN
                dba_action := 'Manual fixup recommended.';
            ELSE
                dba_action := 'Informational only.             Further action is optional.';
            END IF;
        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
                    -- state 3: fixup successfully run and validated.
                    problem_remedied := true;
                    dba_action := 'None.';
                ELSE
                    IF NOT this_check.fixup_is_detectable THEN
                        -- state 4: fixup reported success and fixup is fundamentally
                        -- not detectable.  Trust result of fixup.
                        problem_remedied := true;
                        dba_action := 'None. Be aware that the fixup   ' ||
                                      'has been successfully run, but  ' ||
                                      'by this fixup''s nature, its     ' ||
                                      'effects are not fully detectable' ||
                                      'in the current environment.     ' ||
                                      'Subsequent preupgrade runs will ' ||
                                      'report failure though the       ' ||
                                      'problem has been remedied for   ' ||
                                      'upgrade. Usually a DB restart is' ||
                                      'required to make the fixup fully' ||
                                      'manifest.';
                    ELSE
                        -- state 5: fixup reported success, but CHECK still fails,
                        -- and the check is supposed to be detectable.
                        problem_remedied := false;

                        dba_action := 'Unexpected failure.  Manual fixup required.  ' ||
                                      'FIXUP reports success, but a RECHECK indicated the problem still exists.';
                    END IF;
                END IF;
            ELSE
                -- state 6: fixup run, but returned failure status.
                problem_remedied := false;
                dba_action := 'Unexpected failure.  Fixup routine was run, but was unable to resolve the issue.  Manual DBA action required.';
            END IF;
        END IF;
    END IF;

    format_long_output(column_format(fixup_cols,
                         new string_array_t(' ', to_char(fixup_id) || '.',
                                            ' ', check_name,
                                            ' ', boolean_string(problem_remedied,'YES','NO'),
                                            ' ', dba_action )));
    return problem_remedied;
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;



PROCEDURE init_messages
IS
  props_file utl_file.file_type;
  props_line VARCHAR2(32767);
  property_name VARCHAR2(4000);
  property_value VARCHAR2(32767);
  equals_index NUMBER;
  check_name VARCHAR2(4000);
  check_subproperty VARCHAR2(4000);
  check_auto_fixup_available BOOLEAN;
  fixup_is_detectable BOOLEAN;
BEGIN
  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');
              fixup_is_detectable := 
                  (upper(properties('CHECK.' || check_name || '.FIXUP_IS_DETECTABLE')) = '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,
                             fixup_is_detectable,
                             properties('CHECK.' || check_name || '.MIN_VERSION_INCLUSIVE'),
                             properties('CHECK.' || check_name || '.MAX_VERSION_EXCLUSIVE') );
          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 init_messages;

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;
  c_default_tablespace SYS.DBA_USERS.DEFAULT_TABLESPACE%TYPE;
  i          NUMBER;
BEGIN
  read_components_properties();

  --
  -- Adjust XDB size numbers according to db_block_size as needed.
  --
  IF is_supported_component('XDB') AND
     db_block_size = 16384 THEN
      cmp_info(supported_component_index('XDB')).ins_def_kbytes :=
          2 * cmp_info(supported_component_index('XDB')).ins_def_kbytes;
  END IF;


  --
  -- Figure out which components will be "processed" by the upgrade.
  -- First find the components that are installed in the
  -- low version db.  Later we'll add components that
  -- need to be installed by the upgrade due to any new
  -- product dependencies.
  --
  -- 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.
  --
  -- If the status is not 99,8 = REMOVED or REMOVING
  -- 12202 - simplify nested SELECTs into a single one.
  OPEN reg_cursor FOR 
     'SELECT r.cid, r.status, r.version, r.schema#, u.name, d.default_tablespace
      FROM sys.registry$ r
      JOIN sys.user$ u on u.user#=r.schema#
      LEFT OUTER JOIN sys.dba_users d on  d.username = u.name
      WHERE r.namespace =''SERVER'' and r.status not in (99,8) and r.cid !=''APEX''';
  LOOP

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

    IF is_supported_component(c_cid) THEN
      -- store_comp( supported_component_index(c_cid), c_schema, c_version, n_status);
      i := supported_component_index(c_cid);
      cmp_info(i).processed := TRUE;
      cmp_info(i).status    := dbms_registry.status_name(n_status);
      cmp_info(i).version   := c_version;
      cmp_info(i).schema    := n_schema;
      cmp_info(i).def_ts    := c_default_tablespace;
    END IF;
  END LOOP;
  CLOSE reg_cursor;


  -- CML: TS: estimate for utlrp later?
    -- Consider MISC (miscellaneous) aka "STATS" 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);
  --
  -- fake the psuedo-component "STATS" to be processed
  -- accept

  IF NOT is_supported_component('STATS') THEN
      internal_error(db_version_1_dot||' STATS component info not found in components.properties file.');
  ELSE
    i := supported_component_index('STATS');
    cmp_info(i).processed := TRUE;
    cmp_info(i).schema := 'SYS';
    EXECUTE IMMEDIATE
      'SELECT default_tablespace FROM sys.dba_users WHERE username =:1'
    INTO cmp_info(i).def_ts
    USING cmp_info(i).schema;
  END IF;


  --
  --    Figure out if any components should be "installed."
  --    If new product dependencies are introduced in a version
  --    check if that version boundary is crossed by this upgrade
  --    and if the dependency is not satisfied.
  --
  --    12.1.0.1 - no new product dependencies
  --    12.1.0.2 - no new product dependencies
  --    12.2.0.1 - no new product dependencies
  --    12.2.0.2 - no new product dependencies
  --

  -- none at this time.

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
  message VARCHAR2(100) := '';  -- error msg if this procedure is called for a
                                -- parameter that we do not size for memory
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;
  ELSE
    message := 'parameter ' || name || ' is not recognized for memory sizing';
    RAISE_APPLICATION_ERROR (-20000, message);
  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;


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 analyze_params
IS
  props_file utl_file.file_type;
  props_line VARCHAR2(800);
  param_name VARCHAR2(256);
  param_type VARCHAR2(256);
  indx NUMBER;
  comma_index NUMBER;
  prop_filename VARCHAR(32) := 'parameters.properties';
BEGIN
      props_file := utl_file.fopen('PREUPGRADE_DIR', prop_filename, 'r',32767);
      LOOP
          BEGIN
              utl_file.get_line(props_file, props_line);

              --
              --   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
                  comma_index := instr(props_line, ',');
                  param_name := trim(substr(props_line, 1, comma_index-1));
                  param_type := upper(substr(props_line, comma_index + 1));

                  IF all_parameters.exists(param_name) THEN
                      -- If there are duplicate entries, the later value
                      -- will override the previous value 
                      IF (param_type='DEPRECATED') THEN
                          all_parameters(param_name).is_deprecated := true; 
                          all_parameters(param_name).is_obsoleted := false;
                      ELSIF (param_type='OBSOLETE') OR (param_type='REMOVED') THEN
                          all_parameters(param_name).is_obsoleted := true;
                          all_parameters(param_name).is_deprecated := false;
                      ELSE
                          internal_error('Invalid ' || prop_filename ||
                              ' line due to unknown attribute while processing: ' || 
                              props_line);
                      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
      internal_error('Cannot open the ' || prop_filename ||
          ' from the directory object preupgrade_dir');
      RAISE;
END analyze_params;


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;

  analyze_params();

  -- Sessions removed for XE upgrade only
  IF db_is_XE THEN
      IF all_parameters.exists('sessions') THEN
          all_parameters('sessions').is_obsoleted := true;
      END IF;
  END IF;


  --
  -- 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');

  -- Initialization Parameters Renamed in Release 12.2 --
  store_renamed_param('_db_new_lost_write_protect',
                    '_db_shadow_lost_write_protect'); 
  --
  -- 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);
      IF all_parameters.exists('db_block_buffers') THEN
          all_parameters('db_block_buffers').is_obsoleted := true;
      END IF;
      IF all_parameters.exists('buffer_pool_keep') THEN
          all_parameters('buffer_pool_keep').is_obsoleted := true;
      END IF;
  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;

  -- find minimum processes value for the upgrade
  find_processes_value();

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
BEGIN
    RETURN select_has_rows('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 = '''||tsname||''' AND rownum <= 1');
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
BEGIN
    RETURN select_has_rows('SELECT NULL FROM sys.dba_users
        WHERE username = ''SYS''
        AND temporary_tablespace = '''||tsname||'''');
END ts_is_SYS_temporary;

---------------------- SYS_temp_tablespace_is_a_group ----------------------
-- returns TRUE if the given tablespace_name belongs to a group and the
-- group is the default temp tablespace

FUNCTION SYS_temp_tablespace_is_a_group (tsname VARCHAR2) RETURN BOOLEAN
IS
  flag          NUMBER;
BEGIN
   SELECT count(a.TEMPORARY_TABLESPACE) into flag
   FROM DBA_USERS A, DBA_TABLESPACE_GROUPS  B
   WHERE UPPER(USERNAME)='SYS'
   and a.TEMPORARY_TABLESPACE=B.GROUP_NAME
   and b.TABLESPACE_NAME=''||tsname||'';  
 
    -- true means temp ts belongs to the sys default temp ts group
    IF flag != 0 THEN
        RETURN TRUE;
    ELSE
        RETURN FALSE;
    END IF;
END SYS_temp_tablespace_is_a_group;         


/* 
 *	BMMB BUG 27227129, changing INTEGERS to NUMBER
 */
PROCEDURE init_resources
IS
  idx                 BINARY_INTEGER;
  tmp_cursor          cursor_t;
  tmp_num1            NUMBER;
  tmp_num2            NUMBER;
  delta_queues        NUMBER;
  delta_kbytes        NUMBER := 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           NUMBER;
  default_tablespaces VARCHAR2(4000);
  name                VARCHAR2(128);
  contents            VARCHAR2(128);
  temporary           BOOLEAN;
  localmanaged        BOOLEAN;
  inuse               NUMBER;
  alloc               NUMBER;
  auto                NUMBER;
  avail               NUMBER;
  query               VARCHAR2(4000);
  deftmpts            VARCHAR2(30);
  deftsisgroup        VARCHAR2(5);
  grpsz_kb            NUMBER;
  c_temp_minsz        NUMBER;
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;

  -- Get temporary tablespace for SYS.
  SELECT TEMPORARY_TABLESPACE INTO deftmpts
  FROM DBA_USERS A
  WHERE UPPER(USERNAME)='SYS';

  -- Determine if tablespace is part of a tablespace group?
  SELECT DECODE(COUNT(1), 0,'NO','YES') INTO deftsisgroup
  FROM DBA_TABLESPACE_GROUPS
  WHERE GROUP_NAME=''||deftmpts||'';

  -- Temporary tablespace comes from a TS group
  IF deftsisgroup='YES' THEN
    -- Is the sum of the temp ts enough?
    select sum(b.bytes)/c_kb into grpsz_kb
    from dba_tablespace_groups a join dba_temp_files b
    on(a.tablespace_name=b.tablespace_name)
    where group_name=''||deftmpts||'';

    IF grpsz_kb >= c_temp_minsz_kb THEN
        -- size in bytes
        c_temp_minsz := grpsz_kb * c_kb;
        -- we have enough temp tablespace
       query := '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 
         ),
       tmp_tsgrp as (
         select group_name, tablespace_name, '||c_temp_minsz||' bytes, maxbytes
         from (
           select   a.group_name, a.tablespace_name, b.bytes, b.maxbytes,
                    rank() over (partition by a.group_name order by b.bytes desc) rnk
           from dba_tablespace_groups a join dba_temp_files b
           on(a.tablespace_name=b.tablespace_name)
            )
         WHERE rnk = 1 and rownum = 1
         ),
       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 tmp_tsgrp          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      (dtf.group_name = '''||deftmpts||''')
           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';
    ELSE
        -- we need to increase one temp tablespace
       query := '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 
         ),
       tmp_tsgrp as (
         select group_name, tablespace_name, bytes, maxbytes
         from (
           select   a.group_name, a.tablespace_name, b.bytes, b.maxbytes,
                    rank() over (partition by a.group_name order by b.bytes desc) rnk
           from dba_tablespace_groups a join dba_temp_files b
           on(a.tablespace_name=b.tablespace_name)
            )
         WHERE rnk = 1 and rownum = 1
         ),
       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 tmp_tsgrp          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      (dtf.group_name = '''||deftmpts||''')
           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';
    END IF;

  ELSE
    query := '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 = '''||deftmpts||''')
           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';
  END IF;

  OPEN tmp_cursor FOR query 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;

      IF debug THEN
        dbms_output.put_line(name || crlf ||
                          '  temp: ' || boolean_string(temporary,'TRUE','FALSE') || crlf ||
                          '  localmanaged: ' || boolean_string(localmanaged,'TRUE', 'FALSE') || crlf ||
                          '  inuse:        ' || to_char(inuse) || crlf ||
                          '  alloc:        ' || to_char(alloc) || crlf ||
                          '  auto:         ' || to_char(auto) || crlf ||
                          '  avail:        ' || to_char(avail) );
      END IF;
  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
  
  -- is fast recovery area set?
  -- note: fast recovery area can be set without flashback being turned on
  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;
        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
            -- 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;
        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;

    -- check if sys ts belongs to a group
    IF SYS_temp_tablespace_is_a_group(ts_info(t).name) THEN
        -- setting the minimum amount for the sys temp tablespace
        -- which is the group
        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


    -- 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;

    IF debug THEN
      dbms_output.put_line(crlf || '*' || ts_info(t).name || crlf ||
                        '  temp: ' || boolean_string(ts_info(t).temporary,'TRUE','FALSE') || crlf ||
                        '  localmanaged: ' || boolean_string(ts_info(t).localmanaged,'TRUE', 'FALSE') || crlf ||
                        '  inuse:        ' || to_char(ts_info(t).inuse) || crlf ||
                        '  alloc:        ' || to_char(ts_info(t).alloc) || crlf ||
                        '  auto:         ' || to_char(ts_info(t).auto) || crlf ||
                        '  avail:        ' || to_char(ts_info(t).avail) || crlf ||
                        '  min:          ' || to_char(ts_info(t).min) || crlf ||
                        '  inc_by:       ' || to_char(ts_info(t).inc_by) || crlf ||
                        '  addl:         ' || to_char(ts_info(t).addl) );
    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).temporary THEN
       tmp_varchar2 := 'DBA_TEMP_FILES';
    ELSE
       tmp_varchar2 := 'DBA_DATA_FILES';
    END IF;
    BEGIN
       EXECUTE IMMEDIATE 'SELECT FILE_NAME FROM ' || tmp_varchar2 ||
                      ' WHERE TABLESPACE_NAME = :1 
                        AND AUTOEXTENSIBLE = ''YES''
                        AND ROWNUM=1'
       INTO tmp_filename USING ts_info(t).name;
       ts_info(t).fname := tmp_filename;
       ts_info(t).fauto := TRUE;
    EXCEPTION WHEN NO_DATA_FOUND THEN
       ts_info(t).fauto := FALSE;
    END;

    -- once the joins were done if the sys temp ts belong
    -- to a group rename it to the group's name
    IF SYS_temp_tablespace_is_a_group(ts_info(t).name) THEN
        ts_info(t).name := 'TMP_GROUP['|| deftmpts||']';
    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
  minvalue    NUMBER;  -- minimum value to set
  pdbs_para   NUMBER;  -- at most # of pdbs upgrading in parallel at a time
  pdb_batches NUMBER;  -- approximate # of pdb upgrade "cycles"
  name_idx    V$PARAMETER.NAME%TYPE;
  numa_pool   NUMBER;  -- may or may not exist in the sga.  in bytes.
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;

  -- db_cache_size
  memvp(cs_idx).min_value := 48 * c_mb;

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

  -- numa pool
  numa_pool := 0;
  BEGIN
    execute immediate 'select sum(bytes) from v$sgastat
                         where pool=''numa pool'' group by pool'
                      into numa_pool;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN numa_pool := 0;
    WHEN OTHERS THEN RAISE;
  END;

  IF db_is_cdb = FALSE THEN  -- this db is a non-cdb

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

    -- java_pool_size (96M seen but will use 112M, seen in ROOT)
    memvp(jv_idx).min_value := 112 * 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.)
    memvp(sp_idx).min_value := (264 * 2.5) * c_mb;  -- 660Mb

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

  ELSE  -- IF db is a cdb

    pdbs_para := num_pdbs_upg_in_parallel();
    pdb_batches := num_pdb_batches_upg(pdbs_para);

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

    -- java pool
    IF pdbs_para = 1 THEN
      -- ROOT needs 112M while 1 PDB upgrading at a time can use less (at 64M).
      -- if only 1 PDB in a batch, then the bigger value is needed.
      memvp(jv_idx).min_value := 112 * c_mb;
    ELSE
      -- 64M per pdb upgrading in a batch + fudge
      memvp(jv_idx).min_value := ((64 * pdbs_para) + 16) * c_mb;
    END IF;

    -- shared pool
    memvp(sp_idx).min_value := 
      ((264 * 2.5) + ((pdbs_para - 1) * 120) + (db_n_pdbs * 3)) * c_mb;
    --  constant in con id 1 + reserve per pdb upgrade
    -- + reserve for upgraded pdbs that can be mounted or left opened if errors

    -- pga_aggregate_target
    IF pdbs_para = 1 THEN
      -- same as non-cdb
      memvp(pt_idx).min_value := 64 * c_mb;
    ELSE
      memvp(pt_idx).min_value := 320 * c_mb;
    END IF;

  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 + numa_pool;

  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 + numa_pool;

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
  is_db_noncdb  BOOLEAN;      -- is db a non-cdb?  TRUE if yes/FALSE if not
  name_idx      V$PARAMETER.NAME%TYPE;
  mtgval        NUMBER;       -- memory target value
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;

      -- 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).new_value + (256 * c_mb);

      IF (memvp(st_idx).old_value != 0) THEN -- SGA_TARGET in use
        -- compute '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.
        -- set 'newvalue' to larger of the two new derived minimums (see above).
        mtgval := memvp(st_idx).old_value + memvp(pt_idx).old_value + 128*c_mb;
        IF (mtgval > memvp(mt_idx).new_value) THEN
          memvp(mt_idx).new_value := mtgval;
        END IF;
      END IF;

    END IF;
    -- end of mt_idx

    -- 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;

      -- 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).new_value + (128 * c_mb);
    END IF;

    -- do not set display to TRUE for these params:
    --   memory_target, db_cache_size, java_pool_size,
    --   shared_pool_size, large_poolsize, 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
  memvp(cs_idx).display := FALSE;  -- db cache size

  -- 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
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.
  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;

  -- calculate memory_target 'newvalue' (new derived minimum) based on
  -- mt_idx.min_value and user-specified pool sizes.
  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;

  -- 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;

--
-- return # of PDBs upgrading in parallel
--
FUNCTION num_pdbs_upg_in_parallel RETURN NUMBER
IS
  pdbs_para   NUMBER;  -- at most # of pdbs upgrading in parallel at a time
BEGIN

  -- if this is a non-cdb, then return 0
  IF (db_is_cdb = FALSE) THEN
    return 0;
  END IF;

  -- if this 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;

  return pdbs_para;
END num_pdbs_upg_in_parallel;


--
-- input: # of pdbs upgrading in parallel.
-- if input is 0, return 0.
-- if input is -1, then this function will ignore input argument and
--   determine # of pdbs upgrading in parallel.
--
-- return # of PDB batches/cycles to upgrade.
--
FUNCTION num_pdb_batches_upg (pdbs_in_parallel NUMBER) RETURN NUMBER
IS
  pdbs_para    NUMBER;  -- at most # of pdbs upgrading in parallel at a time
  pdb_batches  NUMBER;  -- # of batches spent to upgrade PDBs
BEGIN

  pdbs_para := pdbs_in_parallel;

  -- if input arg is 0, then return 0 batches
  -- OR
  -- if this is a non-cdb, then return 0
  IF (pdbs_para = 0) OR (db_is_cdb = FALSE) THEN
    return 0;
  END IF;

  -- if input is -1, then caller wants this function to calculate # of pdbs
  -- upgrading in parallel
  IF (pdbs_para = -1) THEN
    pdbs_para := num_pdbs_upg_in_parallel();
  END IF;

  -- estimate # of pdb upgrade cycles

  -- 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

  pdb_batches := ceil(db_n_pdbs/pdbs_para);

  return pdb_batches;
END num_pdb_batches_upg;

--
-- ***********************************************************************
--                         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;
    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;	
    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);
	result_clob := result;
        this_line_end_index := instr(result_clob, crlf, this_line_start_index);
        WHILE (this_line_end_index <> 0) LOOP
            IF this_line_end_index-this_line_start_index > 32767 - crlf_length THEN
                -- could only happen in the XML formatted output if a single XML element body
                -- is less than 32767, but when adding in the length of the surrounding XML tag,
                -- on a single line exceeds 32767.  There aren't any such elements, but just in case...
                dbms_output.put_line('Warning: output line too long.  Truncating the following:');
                this_line := substr(result_clob, this_line_start_index, 
                                                 32767 - crlf_length);
            ELSE
                this_line := substr(result_clob, this_line_start_index, 
                                                 this_line_end_index-this_line_start_index);
            END IF;

            IF text_output_mode THEN
                --
                --  this_line may be too long to emit directly to the terminal.
                --  so chop it up.
                --
                this_line := smart_pad(this_line, C_TERMINAL_WIDTH, NULL);
            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 CLOB;
    final_suffix VARCHAR2(100);
    next_line_start NUMBER;
    next_crlf NUMBER;

    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;

    --
    --    Reset this to 0.  preupgradecheck_t_to_text will walk through them and increment this each time.
    --
    preupgradecheck_failure_count := 0; 

    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:');

            next_line_start := 1;
            next_crlf := 1;  -- seed a non-zero dummy value
            WHILE next_crlf <> 0 LOOP
               next_crlf := instr(original_message, crlf, next_line_start);
               IF next_crlf <> 0 THEN
                   utl_file.put_line(fixup_script, substr(original_message, next_line_start, next_crlf - next_line_start));
                   next_line_start := next_crlf + crlf_length;
               END IF;
            END LOOP;
            utl_file.put_line(fixup_script, substr(original_message, next_line_start));

            utl_file.put_line(fixup_script, '    --');
            utl_file.put_line(fixup_script, '    fixup_result := dbms_preup.run_fixup(''' ||
                                             this_check.name || ''',' ||
                                             preupgradecheck_failure_count  || ') AND fixup_result;');

        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 CLOB) RETURN BOOLEAN
IS
    this_check_record check_record_t;
    check_stmt VARCHAR2(300);
    check_result NUMBER;
    min_version_inclusive_ok BOOLEAN;
    max_version_exclusive_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_inclusive_ok := (this_check_record.min_version_inclusive = 'NONE') OR
                      (dbms_registry_extended.compare_versions(db_version_4_dots,
                                        this_check_record.min_version_inclusive,
                                        dbms_registry_extended.occurs(this_check_record.min_version_inclusive, '.')) >= 0 );

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

    IF (min_version_inclusive_ok AND max_version_exclusive_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 CLOB) RETURN NUMBER
IS
    users VARCHAR2(4000);
BEGIN
    users := '';

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

    
    IF (users IS NULL) THEN
        RETURN c_success;
    ELSE
        result_txt := get_failed_check_xml('oracle_reserved_users',
                      new string_array_t(users, db_version_4_dots),
                      null, null);
        RETURN c_failure;
    END IF;
END oracle_reserved_users_check;

FUNCTION get_addl_undo_space RETURN NUMBER

-- Get additional undo space requirement based on # of objects in the database
-- according to undo_space_rows and undo_space_extra constants.

IS
    --
    -- Rows per every 40M extra for undo space
    --
    undo_space_rows          CONSTANT NUMBER := 75000;
    undo_space_extra         CONSTANT NUMBER := 40;
    objects NUMBER;
BEGIN
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OBJ$' INTO objects;
    return ROUND((objects / undo_space_rows) * undo_space_extra);
END get_addl_undo_space;

FUNCTION supported_version_check(result_txt OUT CLOB) 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 CLOB) 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 CLOB) 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 CLOB) RETURN NUMBER
IS
BEGIN
  IF NOT select_has_rows('SELECT distinct NULL FROM sys.wrm$_wr_control
    WHERE dbid != (SELECT dbid FROM v$database)') 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 CLOB) 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 CLOB) RETURN NUMBER
IS
BEGIN
  IF NOT select_has_rows('SELECT NULL FROM sys.registry$ WHERE cid=''EM''
      AND status NOT IN (99,8)') 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 CLOB) RETURN NUMBER
IS
  c_recover_sql_text CONSTANT VARCHAR2(250) :=
        'SELECT NULL FROM v$recover_file WHERE ((error <> ''OFFLINE NORMAL'') or (error is null)) 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;

  IF NOT select_has_rows(stmttext) 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 CLOB) RETURN NUMBER
IS
BEGIN
  IF NOT select_has_rows('SELECT NULL FROM v$backup  WHERE
           status = ''ACTIVE'' AND rownum <=1') 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 CLOB) RETURN NUMBER
IS
BEGIN

  IF NOT select_has_rows('SELECT NULL FROM sys.dba_2pc_pending
    WHERE rownum <=1') 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 CLOB) 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 CLOB) 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 CLOB) 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
  --

  IF select_varchar2('SELECT LOG_MODE FROM v$database','NOARCHIVELOG') != 'ARCHIVELOG' THEN
    RETURN c_success;
  END IF;

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

  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 CLOB) 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 CLOB) 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 CLOB) 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 IS NOT NULL 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 CLOB) 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;
 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 IS NOT NULL 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 CLOB) RETURN NUMBER
IS
  query  VARCHAR2(4000);
BEGIN
  -- Use schemas from registry$ tables and from user$ (12.1)
  query := 'SELECT 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';

  IF NOT select_has_rows(query) THEN
      RETURN c_success;
  END IF;
  -- 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;
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 IS NOT NULL 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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;


-- WARNING check, with POST upgrade fixup
-- Failure if dbms_utility function does not exist,
-- Failure if it does exist and the check is being run in the target release and
--    any problem objects are found (for post-upgrade-fixup check);
-- Success if it does exist in the old release, even if problem directories are found 
--    - the PRE dir_symlinks_exist_check will handle that scenario.
FUNCTION dir_symlinks_check (result_txt OUT CLOB) RETURN NUMBER
IS
  dircnt         PLS_INTEGER    :=0;
  symlink_exists NUMBER;
 
  function_not_installed EXCEPTION;
  PRAGMA EXCEPTION_INIT(function_not_installed, -904);  

BEGIN
     FOR dir IN (SELECT directory_name FROM dba_directories) LOOP
       EXECUTE IMMEDIATE 
          'SELECT sys.dbms_utility.directory_has_symlink(:dirname)
           FROM sys.dual'         
       INTO symlink_exists USING IN dir.directory_name;
       IF symlink_exists = 1 THEN
          dircnt:=dircnt+1;
       END IF;
     END LOOP;

     IF dircnt = 0 THEN  -- no directories with symlinks
        RETURN c_success;
     ELSE 
        -- check function found symlinks, but only report for target release.
        IF sys.dbms_registry.release_version = '&C_ORACLE_HIGH_VERSION_4_DOTS' THEN
           result_txt := get_failed_check_xml('dir_symlinks',
                         new string_array_t(), null, null);
           RETURN c_failure;
        ELSE 
           -- if old release, let dir_symlinks_exist check handle, so return success
           RETURN c_success;
        END IF;
     END IF;
   
EXCEPTION
     WHEN function_not_installed THEN -- the dbms_system function has not been backported
        result_txt := get_failed_check_xml('dir_symlinks', 
             new string_array_t(), null, null);
        RETURN c_failure;

END dir_symlinks_check;


-- WARNING check, with PRE upgrade fixup
-- Success if the dbms_utility function does not exist 
--   - the POST dir_symlinks_check will handle that scenario
-- Success if no directories with symlinks found
-- Failure if some directories with symlinks are found; displays list of directories.
FUNCTION dir_symlinks_exist_check (result_txt OUT CLOB) RETURN NUMBER
IS
  dircnt         PLS_INTEGER    :=0;
  dirlist        VARCHAR2(4000) := '';
  symlink_exists NUMBER;
 
  function_not_installed EXCEPTION;
  PRAGMA EXCEPTION_INIT(function_not_installed, -904);  

BEGIN
     FOR dir IN (SELECT directory_name FROM dba_directories) LOOP
        EXECUTE IMMEDIATE 
           'SELECT sys.dbms_utility.directory_has_symlink(:dirname)
            FROM sys.dual'         
        INTO symlink_exists USING IN dir.directory_name;
        IF symlink_exists = 1 THEN
           dircnt:=dircnt+1;
           dirlist := dirlist || dir.directory_name || ', ';
        END IF;
     END LOOP;

     IF dircnt = 0 THEN  -- no directories with symlinks
        RETURN c_success;
     ELSE
        dirlist := substr(dirlist,1,length(dirlist) - 2) || '.';  -- remove last comma
        result_txt := get_failed_check_xml('dir_symlinks_exist',
                     new string_array_t(dircnt, dirlist), null, null);
        RETURN c_failure;
     END IF;
   
EXCEPTION

     WHEN VALUE_ERROR THEN -- filled up dirlist string, so just show what is there
        result_txt := get_failed_check_xml('dir_symlinks_exist', 
                      new string_array_t(NULL, dirlist ||  ' (incomplete list)'), null, null);
        RETURN c_failure; 
         
     WHEN function_not_installed THEN 
         -- the dbms_utility function has not been backported, so POST check will be used.
         RETURN c_success;

END dir_symlinks_exist_check;


FUNCTION olap_page_pool_size_check (result_txt OUT CLOB) RETURN NUMBER
IS
  status NUMBER;
BEGIN
     -- skip check if olap_page_pool_size not in all_parameters
     IF (all_parameters.exists('olap_page_pool_size') = FALSE) THEN
       RETURN c_success;
     END IF;

    -- if olap_page_pool_size has not been set explicitly, return success
    IF (all_parameters('olap_page_pool_size').isdefault = 'TRUE') THEN
      RETURN c_success;
    END IF;
      
    -- if olap_page_pool_size is non-zero, then return failure
    IF (all_parameters('olap_page_pool_size').value > 0) THEN
      result_txt := get_failed_check_xml('olap_page_pool_size',
                        new string_array_t(), null, null);
      RETURN c_failure;
    ELSE
      RETURN c_success;
    END IF;
END olap_page_pool_size_check;

FUNCTION purge_recyclebin_check (result_txt OUT CLOB) 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 CLOB) RETURN NUMBER
IS
BEGIN

  IF select_number('SELECT value FROM v$parameter WHERE
          name=''job_queue_processes''', -1) <> 0 THEN
    RETURN c_success;
  ELSE
    result_txt := get_failed_check_xml('job_queue_process_0',
                    new string_array_t(),
                    null, null);

    RETURN c_failure;
  END IF;
END job_queue_process_0_check;


FUNCTION upg_by_std_upgrd_check (result_txt OUT CLOB) 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..cmp_info.count LOOP
        IF cmp_info(i).cid = 'STATS' THEN
          --
          -- the "STATS" (aka MISC) component is a pseudo-component.
          -- it was created for computational convenience only.  Skip it from the XML.
          --
          continue;
        END IF;

        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;


FUNCTION xbrl_version_check (result_txt OUT CLOB) RETURN NUMBER
IS
BEGIN
  IF NOT select_has_rows('SELECT NULL FROM sys.user$ WHERE name=''XBRLSYS''') 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_manual_upgrade_check  (result_txt OUT CLOB) RETURN NUMBER
IS
  db_full_apex_version VARCHAR2(40);
BEGIN
  BEGIN
    SELECT version INTO db_full_apex_version 
    FROM sys.registry$ WHERE cid = 'APEX' and namespace='SERVER';
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      -- no APEX, no problem.
      return c_success;
  END;
  
  --
  -- If the APEX major version is less than the required APEX minimum version, then
  -- the check does not pass, and customers must upgrade APEX before upgrading to
  -- the new SERVER release.
  --

  IF (dbms_registry_extended.compare_versions(db_full_apex_version, high_version_apex, 1) < 0)
    THEN
    result_txt := get_failed_check_xml('apex_manual_upgrade',
                    new string_array_t(db_full_apex_version, high_version_apex),
                    null, null);
    return c_failure;
  ELSE
    return c_success;
  END IF;
END apex_manual_upgrade_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 CLOB) 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 CLOB) 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 CLOB) RETURN NUMBER
IS
dictionary_stats_recent  NUMBER;
doc_name                 VARCHAR2(80) := '';  -- holds the name of the doc that
                                              -- points to the section on
                                              -- managing optimizer statistics

BEGIN
  dictionary_stats_recent := select_number(' 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) ' , 0);

  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 CLOB) RETURN NUMBER
IS
  hidden_params_cursor  cursor_t;
  hidden_param          SYS.V$PARAMETER.NAME%TYPE;
  hidden_param_count    NUMBER := 0;
  hidden_params         VARCHAR2(4000) := '';
  in_rolling_upgrade    VARCHAR2(10);
BEGIN

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

    LOOP
        FETCH hidden_params_cursor INTO hidden_param;
        EXIT WHEN hidden_params_cursor%NOTFOUND;
        BEGIN
            -- Verify the hidden_param is not marked as obsolete
            -- because it could be removed, if so, avoid put it
            -- in the recommendation section to do not cause confusion
            IF NOT all_parameters(hidden_param).is_obsoleted OR
               all_parameters(hidden_param).is_obsoleted IS NULL THEN

                IF hidden_param = '_allow_compatibility_adv_w_grp' THEN
                    -- if we're in a rolling upgrade context
                    -- do not flag _allow_compatibility_adv_w_grp as a
                    -- hidden parameter.
                    BEGIN
                        EXECUTE IMMEDIATE 'SELECT sys_context(''userenv'',''IS_DG_ROLLING_UPGRADE'') FROM DUAL'
                            INTO in_rolling_upgrade;
                        IF in_rolling_upgrade = 'TRUE' THEN
                            CONTINUE;
                        END IF;
                    EXCEPTION
                        WHEN NO_DATA_FOUND THEN
                            -- pre 12.1.0.1 versions of Oracle do not have IS_DG_ROLLING_UPGRADE
                            NULL;
                    END;
                END IF;
                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 IF;
         EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
        END;    

    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 CLOB) 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 CLOB) 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(to_char(audit_record_count)),
                        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 post_fixed_objects_check            (result_txt OUT CLOB) RETURN NUMBER
IS
doc_name              VARCHAR2(80) := '';

BEGIN
-- this CHECK always fails... it always produces the recommendations.

   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('post_fixed_objects',
                                      new string_array_t(doc_name),
                                      null, null);

   RETURN c_failure;
END post_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 CLOB) RETURN NUMBER
IS
dictionary_stats_recent  NUMBER;
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;

  dictionary_stats_recent := select_number('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'')) ', 0);

  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 CLOB) 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 CLOB) 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),
                  null, null);
        RETURN c_failure;
  END IF;
END overlap_network_acl_check;


FUNCTION repcat_setup_check (result_txt OUT CLOB) 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 CLOB) 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 CLOB) RETURN number
IS
BEGIN

  IF NOT select_has_rows('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)') THEN
    RETURN c_success;
  END IF;
  result_txt := get_failed_check_xml('uniaud_tab',
                    new string_array_t(),
                    null, null);
  RETURN c_failure;
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 CLOB) RETURN NUMBER
IS
BEGIN
    IF NOT select_has_rows('select null from sys.dba_triggers
        where trigger_name=''DBMS_JAVA_DEV_TRG'' and owner=''SYS''
        and status=''ENABLED''') THEN
        RETURN c_success;
    END IF;
    -- 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;
END jvm_mitigation_patch_check;

FUNCTION post_jvm_mitigat_patch_check (result_txt OUT CLOB) RETURN NUMBER
IS
BEGIN
    IF NOT select_has_rows('select null from sys.dba_triggers
    where trigger_name=''DBMS_JAVA_DEV_TRG'' and owner=''SYS''
    and status=''ENABLED''') THEN
        RETURN c_success;
    END IF;
    -- 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;
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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) 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 CLOB) RETURN NUMBER
IS
BEGIN
    IF NOT select_has_rows('select 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') THEN
        RETURN c_success;
    END IF;
    -- 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;
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 CLOB) 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 CLOB) RETURN NUMBER
IS
  only_10g_password_ver_present number;
  sqlnetvalue VARCHAR2(20):='';
  file        utl_file.file_type;
BEGIN
  --read buffer
  file := utl_file.fopen('PREUPGRADE_DIR','checksBuffer.tmp','R');
  if utl_file.is_open(file) then
    loop
      begin
        -- get value of sqlnet.ora found from java
        utl_file.get_line(file, sqlnetvalue);
        exception when no_data_found then exit;
      end;
    end loop;
    utl_file.fclose(file);
  end if;
  --
  -- 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 ((sqlnetvalue = '8' or sqlnetvalue = '9' or 
       sqlnetvalue = '10' or sqlnetvalue = '11') 
       and only_10g_password_ver_present > 0) then
      -- throw error
      result_txt := get_failed_check_xml('exclusive_mode_auth',
                new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS),
                null, null);
      return c_failure;
  else
     return c_success;
  end if;
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 CLOB) RETURN NUMBER
IS
  dest_name          VARCHAR2(256) := '';  -- e.g. LOG_ARCHIVE_DEST_1
  destination        VARCHAR2(256) := '';  -- path to archived logs
  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;


/**
	Displays information about the number of cycles that the upgrade
	will take for the cdb upgrade of ROOT, SEED, and PDBs.
**/
FUNCTION cycle_number_check (result_txt OUT CLOB) RETURN NUMBER
IS
	pdbs_para NUMBER;
	n_cycles NUMBER;
BEGIN
	pdbs_para := num_pdbs_upg_in_parallel();
	IF(db_is_cdb) THEN
		result_txt := get_failed_check_xml('cycle_number',
	      			  new string_array_t(db_n_pdbs, pdbs_para),
	        		  null, null);
		RETURN C_FAILURE;
	END IF;
	RETURN C_SUCCESS;
END cycle_number_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 CLOB) RETURN NUMBER
IS
  db_recovery_modes  VARCHAR2(80)  := '';  -- archivelog, flashback
  db_recovery_logs   VARCHAR2(80)  := '';  -- archived logs, flashback logs

BEGIN

  -- archive logs can be in the archive destination
  -- or in db recovery area (fra).  so lets find out
  IF db_log_mode = 'ARCHIVELOG' THEN  -- if ARCHIVING ON
    db_recovery_modes := 'archivelog mode';  -- recovery mode: archive only
    -- what type of logs are in FRA?
    IF is_archivelog_in_fra = TRUE THEN
      db_recovery_logs := 'archived logs';  -- archived logs
    ELSE
      db_recovery_logs := '';  -- not archived logs
    END IF;
  END IF;

  -- flashback logs can only be in fra.
  -- but are the archivelogs in the fra too?
  IF db_flashback_on = TRUE THEN  -- if FLASHBACK on
    db_recovery_modes := 'archivelog and flashback';  -- recovery mode: both
    -- what type of logs are in FRA?
    IF is_archivelog_in_fra = TRUE THEN
      db_recovery_logs  := 'archived and flashback logs';  -- logs: both types
    ELSE
      db_recovery_logs  := 'flashback logs';  -- only 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;


-- *****************************************************************
--     javavm_status_check Section
--
-- Determine whether the javavm state is the appropriated to upgrade
--
-- *****************************************************************
FUNCTION javavm_status_check (result_txt OUT CLOB) RETURN NUMBER
IS
  javavm      VARCHAR2(20):='ok';
  error       VARCHAR2(20);
  message     VARCHAR2(1000);
BEGIN

    IF sys.dbms_registry.is_loaded('JAVAVM') IS NOT NULL THEN
        BEGIN
            EXECUTE IMMEDIATE 'declare junk varchar2(10):=dbms_java.longname(''foo''); begin null; end;';
        EXCEPTION
            WHEN OTHERS THEN 
                javavm  := 'notok'; 
                error   := SQLCODE;
                message := SQLERRM;
        END;
    END IF;

    if (javavm='ok') then
        RETURN c_success;
    end if;
        result_txt := get_failed_check_xml('javavm_status',
                         new string_array_t(error, message), null, null);
    RETURN c_failure;
END javavm_status_check;

-- *****************************************************************
--     tempts_notempfile_check Section
-- Detects where the default temporary tablespace has no temp file
-- *****************************************************************
FUNCTION tempts_notempfile_check (result_txt OUT CLOB) RETURN NUMBER
IS
  deftsisgroup      VARCHAR2(5):='';
  valid_scenario    VARCHAR2(5):='';
  deftmpts          VARCHAR2(4000):='';
  t_deftmpts        VARCHAR2(4000):='';
  p_tablespace_name VARCHAR2(30):='';
  xcursor           SYS_REFCURSOR;
  groupts           NUMBER:=0;
  inv_ts            NUMBER:=0;
  cols              number_array_t:= new number_array_t(0,30,0,30,12);
BEGIN
    -- Get temporary tablespace for SYS.
    SELECT TEMPORARY_TABLESPACE INTO deftmpts
    FROM DBA_USERS A
    WHERE UPPER(USERNAME)='SYS';

    -- Determine if tablespace is part of a tablespace group?
    SELECT DECODE(COUNT(1), 0,'NO','YES') INTO deftsisgroup
    FROM DBA_TABLESPACE_GROUPS
    WHERE GROUP_NAME=''||deftmpts||'';

    -- Temporary tablespace comes from a TS group
    IF deftsisgroup='YES' THEN

        -- Get how many tablespaces of the group have
        -- temp files associated, we need at least one
        SELECT COUNT(A.TABLESPACE_NAME) INTO groupts
        FROM DBA_TABLESPACE_GROUPS A JOIN DBA_TEMP_FILES B
        ON(A.TABLESPACE_NAME=B.TABLESPACE_NAME)
        WHERE A.GROUP_NAME=''||deftmpts||'';

        -- how many ts are there in the group that have a
        -- temp file associated?
        IF groupts = 0 THEN
            -- No ts with a temp file found, error
            valid_scenario:='NO';
            -- Adding headers to table
            t_deftmpts := column_format(cols, new 
                string_array_t(' ', 'GROUP_NAME', ' ', 'TABLESPACE_NAME', ' '));

            -- Get list of ts without temp file
            OPEN xcursor FOR SELECT TABLESPACE_NAME 
                             FROM DBA_TABLESPACE_GROUPS
                             WHERE GROUP_NAME=''||deftmpts||'';

            LOOP
                FETCH xcursor INTO p_tablespace_name;
                EXIT WHEN xcursor%NOTFOUND;
                  t_deftmpts := t_deftmpts || column_format(cols, new 
                  string_array_t(' ', deftmpts, ' ', p_tablespace_name, ' '));
            END LOOP;
            CLOSE xcursor;
            -- send  t_deftmpts to be displayed
            deftmpts := t_deftmpts;
        ELSE
            -- at least one ts has a temp file, all fine
            valid_scenario:='YES';
        END IF;

    -- Temporary tablespace is not part of a tablespace group
    ELSE

        -- Check how many temp files the ts has
        -- associated 
        SELECT COUNT(TABLESPACE_NAME) INTO inv_ts
        FROM DBA_TEMP_FILES
        WHERE TABLESPACE_NAME=''||deftmpts||'';

        -- Does the ts has a temp file?
        IF inv_ts > 0 THEN
            -- yes, it has at least one, all fine
            valid_scenario:='YES';
        ELSE
            -- No, it hasn't, error
            valid_scenario:='NO';
        END IF;

    END IF;

    IF valid_scenario='YES' THEN
        RETURN c_success;
    ELSE
        result_txt := get_failed_check_xml('tempts_notempfile',
                    new string_array_t(deftmpts), null, null);
        return c_failure;
    END IF;

END tempts_notempfile_check;

-- *****************************************************************
--     pga_aggregate_limit_check Section
-- Detects where the user has specified pga_aggregate_limit in spfile
-- that is too small.
-- *****************************************************************
FUNCTION pga_aggregate_limit_check (result_txt OUT CLOB) RETURN NUMBER
IS
    pga_limit_min         NUMBER := 0;
    processes             NUMBER := 0;
    memory_max_target     NUMBER := 0;
    pga_limit_default_min NUMBER := 0;
    pga_limit_proc_min    NUMBER := 0;
BEGIN

    -- skip check if pga_aggregate_limit not in all_parameters
    IF (all_parameters.exists('pga_aggregate_limit') = FALSE) THEN
      RETURN c_success;
    END IF;
    
    -- if pga_aggregate_limit has not been set explicitly, return success
    IF (all_parameters('pga_aggregate_limit').isdefault = 'TRUE') THEN
      RETURN c_success;
    END IF;

    IF (all_parameters('memory_target').value > 0) THEN
      pga_limit_min := all_parameters('memory_max_target').value;
    ELSE

      IF (all_parameters('pga_aggregate_target').value > 0) THEN
        pga_limit_min := all_parameters('pga_aggregate_target').value * 2; 
      END IF;

    END IF;

    -- pga_aggregate_limit must be at least 2GB
    pga_limit_default_min := (2 * c_gb);

    IF (pga_limit_min < pga_limit_default_min) THEN
      pga_limit_min := pga_limit_default_min;
    END IF;

    -- pga_aggregate_limit must be at least (3M * processes)
    processes := all_parameters('processes').value;
    pga_limit_proc_min := (processes * (3 * c_mb));

    IF (pga_limit_min < pga_limit_proc_min) THEN
      pga_limit_min := pga_limit_proc_min; 
    END IF;

    -- user specified value must be >= calculated default
    IF (all_parameters('pga_aggregate_limit').value >= pga_limit_min) THEN
      RETURN c_success;
    ELSE
      result_txt := get_failed_check_xml(
        'pga_aggregate_limit',
        new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS,                -- {1}
                           all_parameters('pga_aggregate_limit').value, -- {2}
                           pga_limit_min),                              -- {3}
        null, null);

      -- set the value for the DBUA xml file
      pga_limit_min_dbua := pga_limit_min; 

      RETURN c_failure;
    END IF;

END; 

-- *****************************************************************
--     dv_simulation_check Section
-- This function checks whether simulation log records prior to upgrade
-- have been moved to DVSYS.OLD_SIMULATION_LOG$ and lets the customer
-- know that post-upgrade.
-- *****************************************************************
FUNCTION dv_simulation_check (result_txt OUT CLOB) RETURN NUMBER
IS
BEGIN
    IF ((sys.dbms_registry.is_loaded('DV') IS NOT NULL) AND
        (sys.dbms_registry.get_progress_value('DV', 'SIMULATION LOGS') =
  'The existing simulation logs have been moved to dvsys.old_simulation_log$'))
    THEN
      result_txt := get_failed_check_xml('dv_simulation',
                       new string_array_t(), null, null);
      RETURN c_failure;
    ELSE
      RETURN c_success;
    END IF;
END dv_simulation_check;

FUNCTION parameter_min_val_check (result_txt OUT CLOB) RETURN NUMBER
IS
    this_parameter_name SYS.V$PARAMETER.NAME%TYPE;
    this_parameter parameter_record_t;
    message_parameters string_array_t;
    message_parameters_index NUMBER;
    found_problem BOOLEAN := false;
    upgrade_requirement VARCHAR2(1);
BEGIN
    message_parameters := new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS);

    message_parameters_index := message_parameters.count();

    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 its min_value
                IF to_number(this_parameter.value) < this_parameter.min_value THEN
                    --
                    --    parameter fails to meet minimum.  add parameter info to array for message.
                    --
                    found_problem := true;

                    --
                    --    we will put an asterisk next to parameters whose minimum
                    --    value settings are required only for the Upgrade (as opposed to
                    --    meeting a minimum setting for the new release in general)
                    --
                    IF (db_is_cdb = FALSE OR db_is_root = TRUE) AND
                       (sys.dbms_preup.is_size_this_memparam(this_parameter.name))
                    THEN
                        upgrade_requirement := '*';
                    ELSE
                        upgrade_requirement := ' ';
                    END IF;

                    message_parameters.extend(4);    -- about to add 4 new indexes in code below
                    message_parameters(message_parameters_index+1) := upgrade_requirement;
                    message_parameters(message_parameters_index+2) := this_parameter.name;
                    message_parameters(message_parameters_index+3) := to_char(this_parameter.value);
                    message_parameters(message_parameters_index+4) := to_char(this_parameter.min_value);
                    message_parameters_index := message_parameters_index + 4;
                END IF;
            END IF;
        END IF;
        this_parameter_name := all_parameters.next(this_parameter_name);
    END LOOP;

    IF found_problem THEN
        result_txt := get_failed_check_xml('parameter_min_val', message_parameters, null, null);
        RETURN c_failure;
    ELSE
        RETURN c_success;
    END IF;
END parameter_min_val_check;


FUNCTION parameter_min_val_fixup        (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER
IS
BEGIN
    -- at this time, we are relying on DBUA to perform the fixup since the
    -- <InitParams> is still present.
    return c_success;
END parameter_min_val_fixup;


FUNCTION parameter_rename_check (result_txt OUT CLOB) RETURN NUMBER
IS
    this_parameter_name SYS.V$PARAMETER.NAME%TYPE;
    this_parameter parameter_record_t;
    message_parameters string_array_t;
    message_parameters_index NUMBER;
    found_problem BOOLEAN := false;
    upgrade_requirement VARCHAR2(1);
BEGIN
    message_parameters := new string_array_t(db_version_3_dots,
        dbms_registry_extended.convert_version_to_n_dots(C_ORACLE_HIGH_VERSION_4_DOTS,3) );

    message_parameters_index := message_parameters.count();

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

        IF ( (this_parameter.isdefault = 'FALSE') AND
             (this_parameter.renamed_to_name IS NOT NULL) AND
             (this_parameter.new_value IS NULL) ) THEN
            --
            --    parameter has been RENAMED and may or may not requre a new VALUE
            --    add parameter info to array for message.
            --
            found_problem := true;

            message_parameters.extend(2);    -- about to add new indexes in code below
            message_parameters(message_parameters_index+1) := this_parameter.name;
            message_parameters(message_parameters_index+2) := this_parameter.renamed_to_name;
            message_parameters_index := message_parameters_index + 2;
        END IF;


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

    IF found_problem THEN
        result_txt := get_failed_check_xml('parameter_rename', message_parameters, null, null);
        RETURN c_failure;
    ELSE
        RETURN c_success;
    END IF;
END parameter_rename_check;


FUNCTION parameter_rename_fixup        (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER
IS
BEGIN
    -- at this time, we are relying on DBUA to perform the fixup since the
    -- <InitParams> is still present.
    return c_success;
END parameter_rename_fixup;


FUNCTION parameter_new_name_val_check (result_txt OUT CLOB) RETURN NUMBER
IS
    this_parameter_name SYS.V$PARAMETER.NAME%TYPE;
    this_parameter parameter_record_t;
    message_parameters string_array_t;
    message_parameters_index NUMBER;
    found_problem BOOLEAN := false;
    upgrade_requirement VARCHAR2(1);
BEGIN
    message_parameters := new string_array_t(C_ORACLE_HIGH_VERSION_4_DOTS);

    message_parameters_index := message_parameters.count();

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

        IF ( (this_parameter.isdefault = 'FALSE') AND
             (this_parameter.renamed_to_name IS NOT NULL) AND
             (this_parameter.new_value IS NOT NULL) ) THEN
            --
            --    parameter has been RENAMED and may or may not requre a new VALUE
            --    add parameter info to array for message.
            --
            found_problem := true;

            message_parameters.extend(3);    -- about to add new indexes in code below
            message_parameters(message_parameters_index+1) := this_parameter.name;
            message_parameters(message_parameters_index+2) := this_parameter.renamed_to_name;
            message_parameters(message_parameters_index+3) := this_parameter.new_value;
            message_parameters_index := message_parameters_index + 3;
        END IF;


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

    IF found_problem THEN
        result_txt := get_failed_check_xml('parameter_new_name_val', message_parameters, null, null);
        RETURN c_failure;
    ELSE
        RETURN c_success;
    END IF;
END parameter_new_name_val_check;


FUNCTION parameter_new_name_val_fixup        (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER
IS
BEGIN
    -- at this time, we are relying on DBUA to perform the fixup since the
    -- <InitParams> is still present.
    return c_success;
END parameter_new_name_val_fixup;


FUNCTION parameter_obsolete_check (result_txt OUT CLOB) RETURN NUMBER
IS
    this_parameter_name SYS.V$PARAMETER.NAME%TYPE;
    this_parameter parameter_record_t;
    message_parameters string_array_t;
    message_parameters_index NUMBER;
    found_problem BOOLEAN := false;
    upgrade_requirement VARCHAR2(1);
BEGIN
    message_parameters := new string_array_t();

    message_parameters_index := message_parameters.count();

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

        IF ( (this_parameter.isdefault = 'FALSE') AND
             (this_parameter.is_obsoleted) ) THEN
            --
            --    parameter has been RENAMED and may or may not requre a new VALUE
            --    add parameter info to array for message.
            --
            found_problem := true;

            message_parameters.extend(1);    -- about to add new indexes in code below
            message_parameters(message_parameters_index+1) := this_parameter.name;
            message_parameters_index := message_parameters_index + 1;

        END IF;


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

    IF found_problem THEN
        result_txt := get_failed_check_xml('parameter_obsolete', message_parameters, null, null);
        RETURN c_failure;
    ELSE
        RETURN c_success;
    END IF;
END parameter_obsolete_check;


FUNCTION parameter_obsolete_fixup        (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER
IS
BEGIN
    -- at this time, we are relying on DBUA to perform the fixup since the
    -- <InitParams> is still present.
    return c_success;
END parameter_obsolete_fixup;


FUNCTION parameter_deprecated_check (result_txt OUT CLOB) RETURN NUMBER
IS
    this_parameter_name SYS.V$PARAMETER.NAME%TYPE;
    this_parameter parameter_record_t;
    message_parameters string_array_t;
    message_parameters_index NUMBER;
    found_problem BOOLEAN := false;
    upgrade_requirement VARCHAR2(1);
BEGIN
    message_parameters := new string_array_t();

    message_parameters_index := message_parameters.count();

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

        IF ( (this_parameter.isdefault = 'FALSE') AND
             (this_parameter.is_deprecated) ) THEN
            --
            --    parameter has been RENAMED and may or may not requre a new VALUE
            --    add parameter info to array for message.
            --
            found_problem := true;
            message_parameters.extend(1);    -- about to add new indexes in code below

            message_parameters(message_parameters_index+1) := this_parameter.name;
            message_parameters_index := message_parameters_index + 1;

        END IF;

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

    IF found_problem THEN
        result_txt := get_failed_check_xml('parameter_deprecated', message_parameters, null, null);
        RETURN c_failure;
    ELSE
        RETURN c_success;
    END IF;
END parameter_deprecated_check;

FUNCTION rollback_segments_check (result_txt OUT CLOB) RETURN NUMBER
IS
    segment_name     SYS.DBA_ROLLBACK_SEGS.SEGMENT_NAME%TYPE;
    tablespace_name  SYS.DBA_SEGMENTS.TABLESPACE_NAME%TYPE;
    status           SYS.DBA_ROLLBACK_SEGS.STATUS%TYPE;
    autox            INTEGER;
    inuse            INTEGER;
    next_extent      SYS.DBA_ROLLBACK_SEGS.NEXT_EXTENT%TYPE;
    max_extents      SYS.DBA_ROLLBACK_SEGS.MAX_EXTENTS%TYPE;
    segment_cursor   cursor_t;

    message_parameters string_array_t;
    message_parameters_index NUMBER;
    found_problem BOOLEAN := false;
BEGIN
    IF db_undo = 'AUTO' THEN  
        return c_success;
    END IF;

    message_parameters := new string_array_t();
    message_parameters_index := message_parameters.count();

    OPEN segment_cursor FOR
        'SELECT r.segment_name, t.tablespace_name, r.status, ' ||
                'round(SUM(DECODE(d.maxbytes, 0, 0, d.maxbytes-d.bytes)/' || to_char(c_kb) || ')) as autox, ' ||
                'ceil(sum(t.bytes)/' || to_char(c_kb) || ') as inuse, ' ||
                'r.next_extent, r.max_extents ' ||
         'FROM SYS.dba_rollback_segs r ' ||
         'JOIN SYS.dba_segments t on r.segment_name = t.segment_name ' ||
         'JOIN sys.dba_data_files d on d.tablespace_name = t.tablespace_name ' ||
         'WHERE r.owner=''PUBLIC'' OR ' ||
               '(r.owner=''SYS'' AND r.segment_name != ''SYSTEM'') ' ||
         'GROUP BY r.segment_name, t.tablespace_name, r.status, r.next_extent, r.max_extents ' ||
         'ORDER BY t.tablespace_name, r.segment_name';
    LOOP
        FETCH segment_cursor INTO segment_name, tablespace_name, status,
                                  autox, inuse, next_extent, max_extents;

        EXIT WHEN segment_cursor%NOTFOUND;

        -- put rollback info in array
        found_problem := true;
        message_parameters.extend(8);    -- about to add new indexes in code below

        message_parameters(message_parameters_index+1) := tablespace_name || '/' || segment_name;
        message_parameters(message_parameters_index+2) := segment_name;
        message_parameters(message_parameters_index+3) := tablespace_name;
        message_parameters(message_parameters_index+4) := status;
        message_parameters(message_parameters_index+5) := boolean_string(autox > 0, 'ON', 'OFF');
        message_parameters(message_parameters_index+6) := displayBytes(inuse * c_kb);
        message_parameters(message_parameters_index+7) := next_extent;
        message_parameters(message_parameters_index+8) := max_extents;


        message_parameters_index := message_parameters_index + 8;

        EXIT WHEN message_parameters_index >= 88;
    END LOOP;
    CLOSE segment_cursor;

    result_txt := get_failed_check_xml( 'rollback_segments', message_parameters, null, null);
    RETURN c_failure;

END rollback_segments_check;



FUNCTION tablespaces_check (result_txt OUT CLOB) RETURN NUMBER
IS
    this_tablespace tablespace_record_t;
    message_parameters string_array_t;
    message_parameters_index NUMBER;
    total_space NUMBER; -- Stores minimum tablespace size needed or the new minimum space needed depending on OBJ$ view.
    local_undo_enabled NUMBER;
    pdbs_para NUMBER;
    inc_by_cnt  NUMBER :=0; -- Counter to store the number of tablespaces needing additional space.
    tbs_action VARCHAR2(30);--The value for this variable could be None, Extend, or Adjust datafile MAXBYTES.
BEGIN
    message_parameters := new string_array_t();
    pdbs_para := num_pdbs_upg_in_parallel();
    message_parameters_index := message_parameters.count();
    execute immediate 'SELECT COUNT(*) FROM DATABASE_PROPERTIES
					   WHERE PROPERTY_NAME=''LOCAL_UNDO_ENABLED'' AND PROPERTY_VALUE=''TRUE'''
  	into local_undo_enabled;
    FOR i IN 1..ts_info.count LOOP
        this_tablespace := ts_info(i);
        IF (this_tablespace.name = db_undo_tbs) THEN
            total_space := this_tablespace.min + get_addl_undo_space();
            --If local undo is enabled, each PDB will have its own UNDO tablespace and reported on its respective log.
            --If local undo is disabled, this means all PDB's are sharing same UNDO tablespace which is created in cdb$root.
            --We will size UNDO tablespace based on the default number of PDB's being upgraded in parallel,
            --the recommended undo space size will be total_space multiplied by the number of pdbs upgraded in parallel. 
            IF (local_undo_enabled = 0 AND pdbs_para > 1) THEN 
            	total_space := total_space * pdbs_para;
            END IF;
        ELSE
            total_space := this_tablespace.min;
        END IF;
        --If the tablespace autoextend is disabled and the inc_by column is bigger than 0, 
        --then the action is to extend the tablespace
        IF ((this_tablespace.inc_by > 0) AND (NOT this_tablespace.fauto)) THEN
        	tbs_action := 'Extend';
        --If it has autoextend enabled but the maxbytes are not enough for the total space
        --then the action is to increase MAXBYTES in the datafile
        ELSIF (this_tablespace.fauto AND (this_tablespace.avail < total_space)) THEN
        	tbs_action := 'Adjust  datafileMAXBYTES';
        ELSE
                tbs_action := 'None';
        END IF;
        IF (tbs_action != 'None') THEN
            inc_by_cnt :=  inc_by_cnt + 1;

            message_parameters.extend(6);    -- about to add new indexes in code below
            message_parameters(message_parameters_index + 1) := this_tablespace.name;
            message_parameters(message_parameters_index + 2) := displayBytes(this_tablespace.alloc * c_mb);
            message_parameters(message_parameters_index + 3) := boolean_string(this_tablespace.fauto, 'ENABLED','DISABLED');        
            message_parameters(message_parameters_index + 4) := displayBytes(total_space * c_mb);
            message_parameters(message_parameters_index + 5) := tbs_action;
            message_parameters(message_parameters_index + 6) := to_char(round(ts_info(i).addl));  -- not displayed
            message_parameters_index := message_parameters_index + 6;
        END IF;
    END LOOP;
    IF (inc_by_cnt > 0) THEN -- If there are tablespaces in the need of adding space, we will print tablespace table and mark check as failed, hence respective preupgrade fixup will be reported. 
    	result_txt := get_failed_check_xml('tablespaces', message_parameters, null, null);
    	RETURN c_failure;
    ELSE 
    	RETURN c_success;
    END IF;

END tablespaces_check;



FUNCTION tablespaces_info_check (result_txt OUT CLOB) RETURN NUMBER
IS
    this_tablespace tablespace_record_t;
    message_parameters string_array_t;
    message_parameters_index NUMBER;
    total_space NUMBER; -- Stores minimum tablespace size needed or the new minimum space needed depending on OBJ$ view.
    local_undo_enabled NUMBER;
    pdbs_para NUMBER;
    inc_by_cnt  NUMBER :=0; -- Counter to store the number of tablespaces needing additional space.
BEGIN
    message_parameters := new string_array_t();
    pdbs_para := num_pdbs_upg_in_parallel();
    message_parameters_index := message_parameters.count();
    execute immediate 'SELECT COUNT(*) FROM DATABASE_PROPERTIES
					   WHERE PROPERTY_NAME=''LOCAL_UNDO_ENABLED'' AND PROPERTY_VALUE=''TRUE'''
  	into local_undo_enabled;
    FOR i IN 1..ts_info.count LOOP
        this_tablespace := ts_info(i);
        IF (this_tablespace.name = db_undo_tbs) THEN
            total_space := this_tablespace.min + get_addl_undo_space();
            --If local undo is enabled, each PDB will have its own UNDO tablespace and reported on its respective log.
            --If local undo is disabled, this means all PDB's are sharing same UNDO tablespace which is created in cdb$root.
            --We will size UNDO tablespace based on the default number of PDB's being upgraded in parallel,
            --the recommended undo space size will be total_space multiplied by the number of pdbs upgraded in parallel. 
            IF (local_undo_enabled = 0 AND pdbs_para > 1) THEN 
            	total_space := total_space * pdbs_para;
            END IF;
        ELSE
            total_space := this_tablespace.min;
        END IF;
         --Only tablespaces that have AUTOEXTEND enabled, the allocated space is less than the total space
        --and MAXBYTES in datafile are not big enough to cover total space needed for upgrade
        --will be shown here as information in order to take in count before the upgrade.
        IF (this_tablespace.fauto) AND
            (total_space > this_tablespace.alloc) AND
            (total_space < this_tablespace.avail) THEN
            inc_by_cnt :=  inc_by_cnt + 1;

            message_parameters.extend(4);    -- about to add new indexes in code below
            message_parameters(message_parameters_index + 1) := this_tablespace.name;
            message_parameters(message_parameters_index + 2) := displayBytes(this_tablespace.alloc * c_mb);
            message_parameters(message_parameters_index + 3) := displayBytes(total_space * c_mb);
            message_parameters(message_parameters_index + 4) := to_char(round(ts_info(i).addl));  -- not displayed
            message_parameters_index := message_parameters_index + 4;
        END IF;
    END LOOP;
    IF (inc_by_cnt > 0) THEN -- If there are autoextend tablespaces in the need of adding space, fail this check.
    	result_txt := get_failed_check_xml('tablespaces_info', message_parameters, null, null);
    	RETURN c_failure;
    ELSE 
    	RETURN c_success;
    END IF;

END tablespaces_info_check;



FUNCTION pre_fixed_objects_check (result_txt OUT CLOB) RETURN NUMBER
IS
  has_stats_cnt  number := 0;  -- # of fixed object tables that have stats
  doc_name       VARCHAR2(80) := '';
BEGIN
  -- find # of fixed object tables that have had stats collected
  execute immediate 'select count(*) from sys.dba_tab_statistics
               where owner = ''SYS'' and table_name like ''X$%''
               and last_analyzed is not null'
  into has_stats_cnt;

  -- if none of the fixed obj tables have had stats collected
  -- then gather fixed objects stats
  -- else do nothing
  if has_stats_cnt > 0 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('pre_fixed_objects',
                    new string_array_t(doc_name),
                    null, null);
      RETURN C_FAILURE;
  end if;
END pre_fixed_objects_check;

FUNCTION pre_fixed_objects_fixup (result_txt IN OUT VARCHAR2, pSqlcode IN OUT NUMBER) RETURN NUMBER
IS
BEGIN
    sys.dbms_stats.gather_fixed_objects_stats;
    RETURN C_SUCCESS;
END pre_fixed_objects_fixup;


--
-- bug 25392096: size for minimum PROCESSES value - 300 or more
-- 
PROCEDURE find_processes_value
IS
  processes_value_now       NUMBER := 0;  -- current value of PROCESSES
  processes_value_to_set    NUMBER := 0;  -- min PROCESSES value to set
  n_background_proc_running NUMBER := 0;  -- # of oracle processes 
                                          --   (minus parallel slaves) running
  n_para_slaves_running     NUMBER := 0;  -- # of parallel slaves running
  n_max_para_slaves_can_run NUMBER := 0;  -- max # of parallel slaves that can
                                          --   run
  n_min_para_slaves_can_run NUMBER := 0;  -- min # of parallel slaves that can
                                          --   run
  para_threads_per_cpu      NUMBER := 0;  -- parallel threads per cpu
  pdbs_para                 NUMBER := 0;  -- default # PDBs that can upgrade
                                          --   in parallel
  n_para_slaves_can_run     NUMBER := 0;  -- estimated # of parallel slaves
                                          --   that can run during the upgrade
  n_user_proc_to_run        NUMBER := 0;  -- estimated # of user processes to
                                          --   to run during the upgrade
  n_total_proc_to_run       NUMBER := 0;  -- total # processes to spawn
                                          --   during upgrade
BEGIN

  -- minimum value for PROCESSES for the upgrade is 300
  store_minval_param('processes', &C_DEFAULT_PROCESSES);

  -- find value of PROCESSES currently set
  execute immediate 'select value from sys.v$parameter  
                       where name = ''processes'''
                    into processes_value_now;

  -- if PROCESSES currently set is less than our minimum (300) THEN set
  -- min value to 300
  IF processes_value_now < all_parameters('processes').min_value THEN
    processes_value_now := all_parameters('processes').min_value;
  END IF;

  -- find # of oracle processes (minus parallel slaves) running
  execute immediate 'select count(*) from sys.v$process 
                       where pname is not null and pname not like ''P0%'''
                    into n_background_proc_running;

  -- find # of parallel slaves currently running in lower version home
  execute immediate 'select count(*) from sys.v$process 
                       where pname like ''P0%'''
                    into n_para_slaves_running;

  -- find min # of parallel slaves that can run
  execute immediate 'select value from sys.v$parameter  
                         where name = ''parallel_min_servers'''
                      into n_min_para_slaves_can_run;

  -- if # of parallel slaves currently running (n_para_slaves_running) is 0
  --   OR less than parallel_min_servers (n_min_para_slaves_can_run), then
  --   lets set n_para_slaves_running to the higher value
  -- in upgrade mode, looks like there's 0 parallel slaves running even if
  --   parallel_min_servers is not 0.
  IF (n_para_slaves_running < n_min_para_slaves_can_run) THEN
    n_para_slaves_running := n_min_para_slaves_can_run;
  END IF;

  IF debug THEN
    dbms_output.put_line('CML 5 PROCESSES: para slaves '
                         || n_para_slaves_running);
  END IF;

  -- find max # of parallel slaves that can run
  execute immediate 'select value from sys.v$parameter  
                       where name = ''parallel_max_servers'''
                    into n_max_para_slaves_can_run;

  -- find value of parallel_threads_per_cpu
  execute immediate 'select value from sys.v$parameter  
                       where name = ''parallel_threads_per_cpu'''
                    into para_threads_per_cpu;

  -- at most # of PDBs upgrading at a time
  pdbs_para := num_pdbs_upg_in_parallel();

  -- estimated # of parallel slaves that can run during the upgrade
  -- there's a SQL in a1201000.sql with parallel hint of 2
  n_para_slaves_can_run := (db_cpus * para_threads_per_cpu) + (pdbs_para * 2);
  IF n_para_slaves_can_run >= n_max_para_slaves_can_run THEN
    n_para_slaves_can_run := n_max_para_slaves_can_run;
  END IF;

  -- # of user processes to run during the upgrade process
  IF pdbs_para = 0 THEN 
    n_user_proc_to_run := 4;  -- 2 catctl.pl processes + 1 datapatch + 1 fudge
  ELSE
    n_user_proc_to_run := pdbs_para * 4;  -- 2 sqlplus sessions + 1 datapatch
                                          -- + 1 fudge
  END IF;

  IF debug THEN
    dbms_output.put_line('CML1 PROCESSES: ' || n_background_proc_running
                         ||  ' ' || n_user_proc_to_run 
                         || ' ' || n_para_slaves_can_run
                         || ' ' || n_para_slaves_running);
  END IF;

  -- # of max processes that can run during upgrade
  IF (n_para_slaves_can_run <= n_para_slaves_running)
  THEN
    n_total_proc_to_run := n_background_proc_running + n_user_proc_to_run
                           + n_para_slaves_running;
    IF debug THEN
      dbms_output.put_line('CML2 PROCESSES: ' || n_total_proc_to_run);
    END IF;
  ELSE
    n_total_proc_to_run := n_background_proc_running + n_user_proc_to_run
                           + n_para_slaves_can_run;
    IF debug THEN
      dbms_output.put_line('CML3 PROCESSES: ' || n_total_proc_to_run);
    END IF;
  END IF;

  -- set new minimum value for PROCESSES if estimate is greater than value set
  -- OR greater than 300
  IF n_total_proc_to_run > processes_value_now THEN
    processes_value_to_set := n_total_proc_to_run;
    store_minval_param('processes', processes_value_to_set);
    IF debug THEN
      dbms_output.put_line('CML4 PROCESSES: ' || processes_value_to_set);
    END IF;
  END IF;
  
END find_processes_value;


-- *****************************************************************
--     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             VARCHAR2(500);    -- sql stmt to run
  rowcount               NUMBER := 0;      -- number of rows returned
  i                      NUMBER := 0;      -- loop counter
  min_pdb_archivelog_gen INTEGER:= 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 := 
    'SELECT count(*) FROM sys.cdb_registry ' ||
    '  WHERE namespace =''SERVER'' AND CON_ID <> 2 AND comp_id =:1 ';

  --
  -- 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 apex sizes should not be included here since apex is not included
  --     in db upgrades to 18 and higher
  --
  FOR i in 1..cmp_info.count LOOP
    IF cmp_info(i).processed THEN
      BEGIN
        EXECUTE IMMEDIATE
          check_stmt
        INTO rowcount
        USING cmp_info(i).cid;
      EXCEPTION
        WHEN NO_DATA_FOUND THEN
          rowcount := 0;
      END;

      IF debug_archive_fra = TRUE THEN
        dbms_output.put_line('ARCHIVE/FRA: ' || cmp_info(i).cid || ' ' ||
                             '# of pdbs ' || rowcount);
      END IF;
 
      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 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 INTEGER:= 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 in the CDB (seed counts as a PDB too), 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;
  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
  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
      -- something wrong if FRA is enabled but no data returned... 
      -- no need to go further, as failure to find recovery area info.
      -- internal_error will raise error and exit
      internal_error('Error in FIND_RECOVERY_AREA step 3a');
    WHEN OTHERS THEN
      -- no need to go further, as failure to find recovery area info.
      -- internal_error will raise error and exit
      internal_error('Error in FIND_RECOVERY_AREA step 3b');
  END; 


  --
  -- 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
      -- something wrong if can't find the info here
      -- raise error and then exit
      internal_error('Error in FIND_RECOVERY_AREA step 4');
  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;


--
--    ##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 UPPER(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.
* 
****************************************************************************************/
  db_VLM_enabled := select_varchar2('SELECT value FROM v$parameter WHERE name =
    ''use_indirect_data_buffers''','NO_DATA') = 'TRUE';

  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;


  --
  -- 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, FRA not set
  tmp_count  := 0;      -- initialize, 0 rows returned
  BEGIN
    EXECUTE IMMEDIATE
      'SELECT count(*)
       FROM sys.v$parameter
       WHERE (name = ''db_recovery_file_dest'' AND value IS NOT NULL)'
    INTO tmp_count;

    -- IF tmp_count >= 1, then db_recovery_file_dest is set.
    -- 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_count >= 1 THEN
      tmp_count := 0;  -- initialize, # of rows returned
      EXECUTE IMMEDIATE
        'SELECT count(*)
         FROM sys.v$parameter
         WHERE (name = ''db_recovery_file_dest_size'' AND value <> ''0'')'
      INTO tmp_count;
      -- IF tmp_count >= 1, then db_recovery_file_dest_size is set.
      IF tmp_count >= 1 THEN
        db_fra_set := TRUE;
      END IF;
    ELSE  -- tmp_count = 0
      db_fra_set := FALSE;  -- db_recovery_file_dest is not set
    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;
  -- end of setting db_fra_set


  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 and dir separator depending on platform
  --
  IF INSTR(db_platform, 'WINDOWS') != 0 THEN
    crlf := CHR(13) || CHR(10);       -- Windows gets the \r and \n
    crlf_length := 2;
    dir_sep := '\';
  ELSE
    crlf := CHR (10);                 -- Just \n for the rest of the world
    crlf_length := 1;
    dir_sep := '/';
  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;

  BEGIN
      EXECUTE IMMEDIATE 'select directory_path from dba_directories
                         where directory_name=''PREUPGRADE_DIR'' and user=''SYS'' '
      INTO preupgrade_dir_path;
      IF substr(preupgrade_dir_path,length(preupgrade_dir_path),1) = dir_sep THEN
          preupgrade_dir_path := substr(preupgrade_dir_path,1,length(preupgrade_dir_path)-1);
      END IF;
  EXCEPTION
      WHEN OTHERS THEN
          -- the PreupgradeDriver.java takes care of setting
          -- PREUPGRADE_DIR, the code here should never execute
          -- and the value is given for debugging help.
          preupgrade_dir_path := 'PREUPGRADE_DIR_is_not_defined';
  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_messages();
  init_components();
  init_resources();
  init_parameters();

  --
  --    Find the properties file with all the CHECK properties
  --



END dbms_preup;
/

show errors;

OHA YOOOO