--MARS-770

set verify off
SET serveroutput ON
--SET TIMING ON
whenever sqlerror exit sql.sqlcode rollback;

column owner format a15
column object_name format a30
column spoolname new_value spoolname 

select 'install_package_MarsGeneralRelease_MARS770_packages_3_' || name || '_' ||to_char(sysdate,'YYYYMMDD_HH24MISS')||'.log' spoolname from v$pdbs;
spool '&spoolname'


prompt ##### started at time #####
select systimestamp from dual;
prompt ##### database name #####
select name pdb_name from v$pdbs;

--set echo on
--=============================================================================================================================
-- start install --MARS-770 payload --CT_MRDS.FILE_MANAGER package
--=============================================================================================================================

CREATE OR REPLACE EDITIONABLE PACKAGE "CT_MRDS"."FILE_MANAGER"
AUTHID CURRENT_USER
AS
   /**
      * General comment for package: Please put comments for functions and procedures as shown in below example.
      * It is a standard.
      * The structure of comment is used by GET_PACKAGE_DOCUMENTATION function 
      * which returns documentation text for confluence page (to Copy-Paste it).
   **/

   -- Example comment:
         /**
            * @name     EX_PROCEDURE_NAME
            * @desc     Procedure description
            * @example  select FILE_MANAGER.EX_PROCEDURE_NAME(pParameter => 129) from dual;
            * @ex_rslt  Example Result
         **/

   TYPE tSourceFileReceived IS RECORD
   (
      A_SOURCE_FILE_RECEIVED_KEY       CT_MRDS.A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY%TYPE,
      A_SOURCE_FILE_CONFIG_KEY         CT_MRDS.A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_CONFIG_KEY%TYPE,
      SOURCE_FILE_PREFIX_INBOX         VARCHAR2(430),
      SOURCE_FILE_PREFIX_ODS           VARCHAR2(430),
      SOURCE_FILE_PREFIX_QUARANTINE    VARCHAR2(430),
      SOURCE_FILE_PREFIX_ARCHIVE       VARCHAR2(430),
      SOURCE_FILE_NAME                 CT_MRDS.A_SOURCE_FILE_RECEIVED.SOURCE_FILE_NAME%TYPE,
      RECEPTION_DATE                   CT_MRDS.A_SOURCE_FILE_RECEIVED.RECEPTION_DATE%TYPE,
      PROCESSING_STATUS                CT_MRDS.A_SOURCE_FILE_RECEIVED.PROCESSING_STATUS%TYPE,
      EXTERNAL_TABLE_NAME              CT_MRDS.A_SOURCE_FILE_RECEIVED.EXTERNAL_TABLE_NAME%TYPE
   );

   cgBL       CONSTANT  VARCHAR2(2)   := CHR(13)||CHR(10);
   vgSourceFileConfigKey   PLS_INTEGER;   
   vgMsgTmp                 VARCHAR2(32000);



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


--   /**
--      * @name     GET_BUCKET_PATH
--      * @desc     Get path to the backet based on pSourceFileConfigKey
--      * @example  select FILE_MANAGER.GET_BUCKET_PATH(pSourceFileConfigKey => 129) from dual;
--      * @ex_rslt  C2D/UC_DISSEM/UC_NMA_DISSEM/
--   **/
--   FUNCTION GET_BUCKET_PATH(
--       pSourceFileConfigKey IN CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY%TYPE
--    )
--   RETURN VARCHAR2;
--
--   /**
--      * @name     GET_BUCKET_PATH
--      * @desc     Get path to the backet based on pSourceKey, 
--      *            and pSourceFileId, pTableId, pParentFolder
--   **/
--   FUNCTION GET_BUCKET_PATH(
--       pSourceKey             IN   CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_KEY%TYPE
--      ,pSourceFileId          IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID%TYPE 
--      ,pTableId               IN   CT_MRDS.A_SOURCE_FILE_CONFIG.TABLE_ID%TYPE
--      ,pParentFolder          IN   VARCHAR2 DEFAULT 'INBOX'
--    )
--   RETURN VARCHAR2;



   /**
      * @name     GET_SOURCE_FILE_CONFIG
      * @desc     Get source file type by matching the source file name against source file type naming patterns 
      *           or by specifying the id of a received source file.
      * @example  ... 
      * @ex_rslt  "CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE"
   **/
   FUNCTION GET_SOURCE_FILE_CONFIG(pFileUri               IN VARCHAR2 DEFAULT NULL
                                 , pSourceFileReceivedKey IN NUMBER   DEFAULT NULL
                                 , pSourceFileConfigKey   IN NUMBER   DEFAULT NULL)
   RETURN CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE;



   /**
      * @name     REGISTER_SOURCE_FILE_RECEIVED
      * @desc     Register a newly received source file in A_SOURCE_FILE_RECEIVED table.
      *           This overload automatically determines source file type from the file name. 
      *           It returns the value of A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY column for newly added record. 
      * @example  vSourceFileReceivedKey := FILE_MANAGER.REGISTER_SOURCE_FILE_RECEIVED(pSourceFileReceivedName => 'INBOX/C2D/UC_DISSEM/UC_NMA_DISSEM/UC_NMA_DISSEM-277740.csv');
      * @ex_rslt  3245
   **/
   FUNCTION REGISTER_SOURCE_FILE_RECEIVED (
      pSourceFileReceivedName IN VARCHAR2
   )
   RETURN PLS_INTEGER;



   /**
      * @name     REGISTER_SOURCE_FILE_RECEIVED
      * @desc     Register a new new source file in A_SOURCE_FILE_RECEIVED table based on pSourceFileReceivedName and pSourceFileConfig.
      *           Then it returns the value of A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY column for newly added record. 
      * @example  vSourceFileReceivedKey := FILE_MANAGER.REGISTER_SOURCE_FILE_RECEIVED(
      *                                         pSourceFileReceivedName => 'INBOX/C2D/UC_DISSEM/UC_NMA_DISSEM/UC_NMA_DISSEM-277740.csv'
      *                                        ,pSourceFileConfig => ...A_SOURCE_FILE_CONFIG%ROWTYPE... );
      * @ex_rslt  3245
   **/
   FUNCTION  REGISTER_SOURCE_FILE_RECEIVED (
      pSourceFileReceivedName IN VARCHAR2,
      pSourceFileConfig IN CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE
   )
   RETURN PLS_INTEGER;



   /**
      * @name     SET_SOURCE_FILE_RECEIVED_STATUS
      * @desc     Set status of file in A_SOURCE_FILE_RECEIVED table - PROCESSING_STATUS column 
      *           based on A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY 
      *           and provided value of pStatus parameter
      * @example  exec FILE_MANAGER.SET_SOURCE_FILE_RECEIVED_STATUS(pSourceFileReceivedKey => 377, pStatus => 'READY_FOR_INGESTION');
   **/
   PROCEDURE SET_SOURCE_FILE_RECEIVED_STATUS(
      pSourceFileReceivedKey IN PLS_INTEGER,
      pStatus IN VARCHAR2
   );



   /**
      * @name     GET_EXTERNAL_TABLE_COLUMNS
      * @desc     Function used to get string with all table columns definitions based on pTargetTableTemplate "TEMPLATE TABLE" name. 
      *           It used for creating "EXTERNAL TABLE" using CREATE_EXTERNAL_TABLE procedure.
      * @example  select FILE_MANAGER.GET_EXTERNAL_TABLE_COLUMNS(pTargetTableTemplate => 'CT_ET_TEMPLATES.LM_STANDING_FACILITIES_HEADER') from dual;
      * @ex_rslt  	"A_KEY" NUMBER(38,0) NOT NULL ENABLE, 
      *              "A_WORKFLOW_HISTORY_KEY" NUMBER(38,0) NOT NULL ENABLE, 
      *              "REV_NUMBER" NUMBER(28,0), 
      *              "REF_DATE" DATE, 
      *              "FREE_TEXT" VARCHAR2(1000 CHAR), 
      *              "MLF_BS_TOTAL" NUMBER(28,10), 
      *              "DF_BS_TOTAL" NUMBER(28,10), 
      *              "MLF_SF_TOTAL" NUMBER(28,10), 
      *              "DF_SF_TOTAL" NUMBER(28,10)
   **/
   FUNCTION GET_EXTERNAL_TABLE_COLUMNS (
      pTargetTableTemplate IN VARCHAR2
   )  
   RETURN CLOB;



   /**
      * @name     CREATE_EXTERNAL_PART_TABLE
      * @desc     TO BE DROPPED - It was created for HISTORIZATION process (HISTORISE_TABLE_DATA procedure), but it is not used there
   **/
   PROCEDURE CREATE_EXTERNAL_PART_TABLE (
      pTableName          IN VARCHAR2,
      pTemplateTableName  IN VARCHAR2,
      pPrefix             IN VARCHAR2,
      pFileName           IN VARCHAR2 DEFAULT NULL,
      pDelimiter          IN VARCHAR2 DEFAULT ',',
      pBucketUri          IN VARCHAR2 DEFAULT ENV_MANAGER.gvInboxBucketUri
   );



   /**
      * @name     CREATE_EXTERNAL_TABLE
      * @desc     A wrapper procedure for DBMS_CLOUD.CREATE_EXTERNAL_TABLE which creates External Table 
      * @example  
      *   begin
      *      FILE_MANAGER.CREATE_EXTERNAL_TABLE(
      *          pTableName         => 'STANDING_FACILITIES_HEADER',
      *          pTemplateTableName => 'CT_ET_TEMPLATES.LM_STANDING_FACILITIES_HEADER',
      *          pPrefix            => 'ODS/LM/STANDING_FACILITIES_HEADER/',
      *          pFileName          => 'https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/frcnomajoc7v/b/mrds_data_tst/o/ODS/LM/STANDING_FACILITIES_HEADER/*.csv',
      *          pDelimiter         => ',',
      *          pBucketUri         => 'https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/frcnomajoc7v/b/mrds_data_tst/o/'
      *         );
      *   end;
   **/
   PROCEDURE CREATE_EXTERNAL_TABLE (
      pTableName          IN VARCHAR2,
      pTemplateTableName  IN VARCHAR2,
      pPrefix             IN VARCHAR2,
      pBucketUri          IN VARCHAR2 DEFAULT ENV_MANAGER.gvInboxBucketUri,
      pFileName           IN VARCHAR2 DEFAULT NULL,
      pDelimiter          IN VARCHAR2 DEFAULT ','
   );



   /**
      * @name     CREATE_EXTERNAL_TABLE
      * @desc     Creates External Table for single file provided by 
      *           pSourceFileReceivedKey parameter (A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY)
      * @example  exec FILE_MANAGER.CREATE_EXTERNAL_TABLE(pSourceFileReceivedKey => 377);;
   **/
   PROCEDURE CREATE_EXTERNAL_TABLE (
      pSourceFileReceivedKey IN NUMBER
   );



   /**
      * @name     VALIDATE_SOURCE_FILE_RECEIVED
      * @desc     A wrapper procedure for DBMS_CLOUD.VALIDATE_EXTERNAL_TABLE 
      *           It validate External table build upon single file 
      *           provided by pSourceFileReceivedKey parameter (A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY)
      * @example  exec FILE_MANAGER.VALIDATE_SOURCE_FILE_RECEIVED(pSourceFileReceivedKey => 377);
   **/
   PROCEDURE VALIDATE_SOURCE_FILE_RECEIVED
   (
      pSourceFileReceivedKey IN NUMBER
   );


   /**
      * @name     VALIDATE_EXTERNAL_TABLE
      * @desc     A wrapper function for DBMS_CLOUD.VALIDATE_EXTERNAL_TABLE.
      *           It validates External Table provided by parameter pTableName.
      *           It returns: PASSED or FAILED.
      * @example 
      *   declare
      *      vStatus           VARCHAR2(100);
      *   begin
      *      vStatus := FILE_MANAGER.VALIDATE_EXTERNAL_TABLE(pTableName => 'STANDING_FACILITIES_HEADER');
      *      DBMS_OUTPUT.PUT_LINE('vStatus = '||vStatus);
      *   end;
      *
      * @ex_rslt  FAILED
   **/
   FUNCTION VALIDATE_EXTERNAL_TABLE(pTableName IN VARCHAR2)
   RETURN VARCHAR2;


   /**
      * @name     S_VALIDATE_EXTERNAL_TABLE
      * @desc     A function which checks if SELECT query reterns any rows.
      *           It trys to selects External Table provided by parameter pTableName.
      *           It returns: PASSED or FAILED.
      * @example 
      *   declare
      *      vStatus           VARCHAR2(100);
      *   begin
      *      vStatus := FILE_MANAGER.S_VALIDATE_EXTERNAL_TABLE(pTableName => 'STANDING_FACILITIES_HEADER');
      *      DBMS_OUTPUT.PUT_LINE('vStatus = '||vStatus);
      *   end;
      *
      * @ex_rslt  PASSED
   **/
   FUNCTION S_VALIDATE_EXTERNAL_TABLE(pTableName IN VARCHAR2)
   RETURN VARCHAR2;



   /**
      * @name     DROP_EXTERNAL_TABLE
      * @desc     It drops External Table for single file provided by 
      *           pSourceFileReceivedKey parameter (A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY)
      * @example  exec FILE_MANAGER.DROP_EXTERNAL_TABLE(pSourceFileReceivedKey => 377);
   **/
   PROCEDURE DROP_EXTERNAL_TABLE (
      pSourceFileReceivedKey IN NUMBER
   );



   /**
      * @name     COPY_FILE
      * @desc     It copies file provided by 
      *           pSourceFileReceivedKey parameter (A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY)
      *           into destination provided by pDestination parameter.
      *           pDestination parameter allowed values are: 'ODS'
      * @example  exec FILE_MANAGER.COPY_FILE(pSourceFileReceivedKey => 377, pDestination => 'ODS');
   **/
   PROCEDURE COPY_FILE(
      pSourceFileReceivedKey  IN NUMBER, 
      pDestination            IN VARCHAR2
   );




   /**
      * @name     MOVE_FILE
      * @desc     It moves file provided by 
      *           pSourceFileReceivedKey parameter (A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY)
      *           into destination provided by pDestination parameter.
      *           pDestination parameter allowed values are: 'ODS', 'QUARANTINE'
      * @example  exec FILE_MANAGER.MOVE_FILE(pSourceFileReceivedKey => 377, pDestination => 'ODS');
   **/
   PROCEDURE MOVE_FILE(
      pSourceFileReceivedKey  IN NUMBER, 
      pDestination            IN VARCHAR2
   );



   /**
      * @name     DELETE_FOLDER_CONTENTS
      * @desc     It deletes all files from specified folder in the cloud storage.
      *           The procedure lists all objects in the specified folder prefix and deletes them one by one.
      *           pBucketName parameter specifies which bucket to use: 'INBOX', 'DATA', 'HISTORY'
      *           pFolderPrefix parameter specifies the folder path within the bucket (e.g., 'C2D/UC_DISSEM/UC_NMA_DISSEM/')
      * @example  exec FILE_MANAGER.DELETE_FOLDER_CONTENTS(pBucketName => 'INBOX', pFolderPrefix => 'C2D/UC_DISSEM/UC_NMA_DISSEM/');
   **/
   PROCEDURE DELETE_FOLDER_CONTENTS(
      pBucketName    IN VARCHAR2,
      pFolderPrefix  IN VARCHAR2
   );




   /**
      * @name     PROCESS_SOURCE_FILE
      * @desc     It process file provided by pSourceFileReceivedName parameter.
      *           Ubmrella procedure that calls:
      *              - REGISTER_SOURCE_FILE_RECEIVED;
      *              - CREATE_EXTERNAL_TABLE;
      *              - VALIDATE_SOURCE_FILE_RECEIVED;
      *              - DROP_EXTERNAL_TABLE;
      *              - MOVE_FILE;
      * @example  exec FILE_MANAGER.PROCESS_SOURCE_FILE(pSourceFileReceivedName => 'INBOX/C2D/UC_DISSEM/UC_NMA_DISSEM/UC_NMA_DISSEM-277740.csv');
   **/
   PROCEDURE PROCESS_SOURCE_FILE(pSourceFileReceivedName IN VARCHAR2)
   ;



   /**
      * @name     PROCESS_SOURCE_FILE
      * @desc     It process file provided by pSourceFileReceivedName parameter and return processing result value.
      *           It returns (success/failure) => 0 / -(value). 
      *           Ubmrella function that calls PROCESS_SOURCE_FILE procedure.
      * @example  
      *           declare
      *              vResult PLS_INTEGER;
      *           begin
      *              vResult := CT_MRDS.FILE_MANAGER.PROCESS_SOURCE_FILE(PSOURCEFILERECEIVEDNAME => 'INBOX/C2D/UC_DISSEM/UC_NMA_DISSEM/UC_NMA_DISSEM-277740.csv');
      *              DBMS_OUTPUT.PUT_LINE('vResult = ' || vResult);
      *           end;
      * @ex_rslt  0
      *           -20021      
   **/
   FUNCTION PROCESS_SOURCE_FILE(pSourceFileReceivedName IN VARCHAR2)
   RETURN PLS_INTEGER;



   /**
      * @name     GET_DATE_FORMAT
      * @desc     Returns date format for specified template table name and column name.
      *           Date is taken from configuration A_COLUMN_DATE_FORMAT table.
      * @example  select FILE_MANAGER.GET_DATE_FORMAT(
      *                       pTemplateTableName => 'STANDING_FACILITIES_HEADER',
      *                       pColumnName        => 'SNAPSHOT_DATE')
      *             from dual;
      * @ex_rslt  DD/MM/YYYY HH24:MI:SS
   **/
   FUNCTION GET_DATE_FORMAT(
      pTemplateTableName IN VARCHAR2,
      pColumnName  IN VARCHAR2
   ) RETURN VARCHAR2;



   /**
      * @name     GENERATE_EXTERNAL_TABLE_PARAMS
      * @desc     It builds two strings: pColumnList and pFieldList for specified Template Table name, by parameter: pTemplateTableName.
      * @example  
      *   declare 
      *      vColumnList CLOB;
      *      vFieldList  CLOB;
      *   begin 
      *      FILE_MANAGER.GENERATE_EXTERNAL_TABLE_PARAMS (
      *         pTemplateTableName => 'CT_ET_TEMPLATES.LM_STANDING_FACILITIES_HEADER'
      *         ,pColumnList         => vColumnList
      *         ,pFieldList          => vFieldList
      *      );
      *      DBMS_OUTPUT.PUT_LINE('vColumnList = '||vColumnList);
      *      DBMS_OUTPUT.PUT_LINE('vFieldList  = '||vFieldList);
      *   end;
      *   /
   **/
   PROCEDURE GENERATE_EXTERNAL_TABLE_PARAMS (
      pTemplateTableName IN VARCHAR2,
      pColumnList  OUT CLOB,
      pFieldList   OUT CLOB
   );


   /**
      * @name     EXPORT_TABLE_DATA
      * @desc     Wrapper procedure for DBMS_CLOUD.EXPORT_DATA.
      *           Exports data into CSV file on OCI infrustructure.
   **/
   PROCEDURE EXPORT_TABLE_DATA (
     pSchemaName      IN VARCHAR2,
     pTableName       IN VARCHAR2,
     pKeyColumnName   IN VARCHAR2,
     pBucketName      IN VARCHAR2,
     pFolderName      IN VARCHAR2,
     pNamespace       IN VARCHAR2 default ENV_MANAGER.gvNameSpace,
     pRegion          IN VARCHAR2 default ENV_MANAGER.gvRegion,
     pCredentialName  IN VARCHAR2 default ENV_MANAGER.gvCredentialName
   )  ;



   /**
      * @name     EXPORT_TABLE_DATA_BY_DATE
      * @desc     Wrapper procedure for DBMS_CLOUD.EXPORT_DATA.
      *           Exports data into PARQUET files on OCI infrustructure.
      *           Each YEAR_MONTH pair goes to seperate file (implicit partitioning).
   **/
   PROCEDURE EXPORT_TABLE_DATA_BY_DATE (
     pSchemaName      IN VARCHAR2,
     pTableName       IN VARCHAR2,
     pKeyColumnName   IN VARCHAR2,
     pBucketName      IN VARCHAR2,
     pFolderName      IN VARCHAR2,
     pMinDate         IN DATE     default DATE '1900-01-01',
     pMaxDate         IN DATE     default SYSDATE,
     pNamespace       IN VARCHAR2 default ENV_MANAGER.gvNameSpace,
     pRegion          IN VARCHAR2 default ENV_MANAGER.gvRegion,
     pCredentialName  IN VARCHAR2 default ENV_MANAGER.gvCredentialName
   )  ;



--   /**
--      * @name     HISTORISE_TABLE_DATA
--      * @desc     Wrapper procedure for DBMS_CLOUD.EXPORT_DATA.
--      *           Exports data from table specified by pSourceFileConfigKey(A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY) into PARQUET file on OCI infrustructure.
--      *           Each YEAR_MONTH pair goes to seperate file (implicit partitioning).
--   **/
--   PROCEDURE HISTORISE_TABLE_DATA (
--      pSourceFileConfigKey   IN CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY%TYPE
--   );
--
--
--
--   /**
--      * @name     GATHER_TABLE_STAT
--      * @desc     Gather info about EXTERNAL TABLE specified by pSourceFileConfigKey parameter (A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY).
--      *           Data is inserted into A_TABLE_STAT and A_TABLE_STAT_HIST.
--   **/
--   PROCEDURE GATHER_TABLE_STAT (
--      pSourceFileConfigKey   IN CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY%TYPE
--   );



   /**
      * @name     ADD_SOURCE
      * @desc     Insert a new record to A_SOURCE table.
      *           pSourceKey is a PRIMARY KEY value.
   **/
   PROCEDURE ADD_SOURCE (
      pSourceKey   IN CT_MRDS.A_SOURCE.A_SOURCE_KEY%TYPE,
      pSourceName  IN CT_MRDS.A_SOURCE.SOURCE_NAME%TYPE
   );



   /**
      * @name     DELETE_SOURCE_CASCADE
      * @desc     Safely deletes a SOURCE specified by pSourceKey parameter from A_SOURCE table and all dependent tables:
      *           - A_SOURCE_FILE_CONFIG
      *           - A_SOURCE_FILE_RECEIVED
      *           - A_COLUMN_DATE_FORMAT (only if template table is not shared with other source systems)
      *           The procedure checks if template tables are shared before deleting date format configurations.
      *           If a template table is used by multiple source systems, date formats are preserved.
      * @example  CALL CT_MRDS.FILE_MANAGER.DELETE_SOURCE_CASCADE(pSourceKey => 'TEST_SYS');
   **/
   PROCEDURE DELETE_SOURCE_CASCADE (
      pSourceKey   IN CT_MRDS.A_SOURCE.A_SOURCE_KEY%TYPE
   );



   /**
      * @name     GET_CONTAINER_SOURCE_FILE_CONFIG_KEY
      * @desc     For specified parameter pSourceFileId (A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID)
      *           it returns A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY for related CONTAINER record.
      * @example  select FILE_MANAGER.GET_CONTAINER_SOURCE_FILE_CONFIG_KEY(
      *                       pSourceFileId => 'UC_DISSEM')
      *             from dual;
      * @ex_rslt  126
   **/
   FUNCTION GET_CONTAINER_SOURCE_FILE_CONFIG_KEY (
      pSourceFileId          IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID%TYPE
   ) RETURN PLS_INTEGER;



   /**
      * @name     GET_SOURCE_FILE_CONFIG_KEY
      * @desc     For specified input parameters,
      *           it returns A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY.
      * @example  select FILE_MANAGER.GET_SOURCE_FILE_CONFIG_KEY (
      *               pSourceFileType        => 'INPUT'
      *              ,pSourceFileId          => 'UC_DISSEM'
      *              ,pTableId               => 'UC_NMA_DISSEM')
      *           from dual;
      * @ex_rslt  126
   **/
   FUNCTION GET_SOURCE_FILE_CONFIG_KEY (
       pSourceFileType        IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_TYPE%TYPE DEFAULT 'INPUT'
      ,pSourceFileId          IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID%TYPE
      ,pTableId               IN   CT_MRDS.A_SOURCE_FILE_CONFIG.TABLE_ID%TYPE
   ) RETURN PLS_INTEGER;



   /**
      * @name     ADD_SOURCE_FILE_CONFIG
      * @desc     Insert a new record to A_SOURCE_FILE_CONFIG table.
   **/
   PROCEDURE ADD_SOURCE_FILE_CONFIG (
       pSourceKey             IN   CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_KEY%TYPE
      ,pSourceFileType        IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_TYPE%TYPE
      ,pSourceFileId          IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID%TYPE
      ,pSourceFileDesc        IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_DESC%TYPE
      ,pSourceFileNamePattern IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_NAME_PATTERN%TYPE
      ,pTableId               IN   CT_MRDS.A_SOURCE_FILE_CONFIG.TABLE_ID%TYPE                  DEFAULT NULL
      ,pTemplateTableName     IN   CT_MRDS.A_SOURCE_FILE_CONFIG.TEMPLATE_TABLE_NAME%TYPE       DEFAULT NULL
      ,pContainerFileKey      IN   CT_MRDS.A_SOURCE_FILE_CONFIG.CONTAINER_FILE_KEY%TYPE        DEFAULT NULL
   );



   /**
      * @name     ADD_COLUMN_DATE_FORMAT
      * @desc     Insert a new record to A_COLUMN_DATE_FORMAT table.
   **/
   PROCEDURE ADD_COLUMN_DATE_FORMAT (
       pTemplateTableName     IN   CT_MRDS.A_COLUMN_DATE_FORMAT.TEMPLATE_TABLE_NAME%TYPE
      ,pColumnName            IN   CT_MRDS.A_COLUMN_DATE_FORMAT.COLUMN_NAME%TYPE
      ,pDateFormat            IN   CT_MRDS.A_COLUMN_DATE_FORMAT.DATE_FORMAT%TYPE
   );



   /**
      * @name     GET_BUCKET_URI
      * @desc     Function used to get string with bucket http url.
      *           Possible input values for pBucketName are: 'INBOX', 'ODS', 'DATA', 'HISTORY'
      * @example  select FILE_MANAGER.GET_BUCKET_URI(pBucketName => 'ODS') from dual;
      * @ex_rslt  https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/frcnomajoc7v/b/mrds_data_tst/o/
   **/
   FUNCTION GET_BUCKET_URI(pBucketName VARCHAR2)
   RETURN VARCHAR2;



   /**
      * @name     GET_DET_SOURCE_FILE_CONFIG_INFO
      * @desc     Function returns details about A_SOURCE_FILE_CONFIG record 
      *           for specified pSourceFileConfigKey (A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY).
      *           If pIncludeContainerInfo    is <> 0 it returns additional info about related Container config record (A_SOURCE_FILE_CONFIG)
      *           If pIncludeColumnFormatInfo is <> 0 it returns additional info about related ColumnFormat config record (A_COLUMN_DATE_FORMAT)
      * @example  select FILE_MANAGER.GET_DET_SOURCE_FILE_CONFIG_INFO (
      *                  pSourceFileConfigKey     => 128
      *                 ,pIncludeContainerInfo    => 1
      *                 ,pIncludeColumnFormatInfo => 1
      *           ) from dual;
      * @ex_rslt  
      * Details about File Configuration:
      * --------------------------------
      * A_SOURCE_FILE_CONFIG_KEY             = 128
      * A_SOURCE_KEY                         = C2D
      * ...
      * --------------------------------
      * 
      *    Details about related Container Config:
      *    --------------------------------
      *    A_SOURCE_FILE_CONFIG_KEY             = 126
      *    A_SOURCE_KEY                         = C2D
      * ...
      *    --------------------------------
      * 
      *       Column Date Format config entries:
      *       --------------------------------
      *       TEMPLATE_TABLE_NAME  = CT_ET_TEMPLATES.C2D_UC_MA_DISSEM
      * ...
      *       --------------------------------
   **/
   FUNCTION GET_DET_SOURCE_FILE_CONFIG_INFO (
        pSourceFileConfigKey     IN CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY%TYPE
       ,pIncludeContainerInfo    IN PLS_INTEGER DEFAULT 1
       ,pIncludeColumnFormatInfo IN PLS_INTEGER DEFAULT 1
   ) RETURN VARCHAR2;



   /**
      * @name     GET_DET_SOURCE_FILE_RECEIVED_INFO
      * @desc     Function returns details about A_SOURCE_FILE_RECEIVED record 
      *           for specified pSourceFileReceivedKey (A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY).
      *           If pIncludeConfigInfo       is <> 0 it returns additional info about related Container config record (A_SOURCE_FILE_CONFIG)
      *           If pIncludeContainerInfo    is <> 0 it returns additional info about related Container config record (A_SOURCE_FILE_CONFIG)
      *           If pIncludeColumnFormatInfo is <> 0 it returns additional info about related ColumnFormat config record (A_COLUMN_DATE_FORMAT)
      * @example  select FILE_MANAGER.GET_DET_SOURCE_FILE_RECEIVED_INFO (
      *                  pSourceFileReceivedKey   => 377
      *                 ,pIncludeConfigInfo       => 1
      *                 ,pIncludeContainerInfo    => 1
      *                 ,pIncludeColumnFormatInfo => 1
      *           ) from dual;
      *
   **/
   FUNCTION GET_DET_SOURCE_FILE_RECEIVED_INFO (
       pSourceFileReceivedKey   IN CT_MRDS.A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY%TYPE
      ,pIncludeConfigInfo       IN PLS_INTEGER DEFAULT 1
      ,pIncludeContainerInfo    IN PLS_INTEGER DEFAULT 1
      ,pIncludeColumnFormatInfo IN PLS_INTEGER DEFAULT 1
   ) RETURN VARCHAR2;



   /**
      * @name     GET_DET_USER_LOAD_OPERATIONS
      * @desc     Function returns details from USER_LOAD_OPERATIONS table
      *           for specified pOperationId.
      * @example  select FILE_MANAGER.GET_DET_USER_LOAD_OPERATIONS (pOperationId   => 3608) from dual;
      * @ex_rslt  
      *           Details about USER_LOAD_OPERATIONS where ID = 3608
      *           --------------------------------
      *           ID                = 3608
      *           TYPE              = VALIDATE
      *           SID               = 31260
      *           SERIAL#           = 52915
      *           START_TIME        = 2025-05-20 10.08.24.436983 EUROPE/BELGRADE
      *           UPDATE_TIME       = 2025-05-20 10.08.24.458643 EUROPE/BELGRADE
      *           STATUS            = FAILED
      *           OWNER_NAME        = CT_MRDS
      *           TABLE_NAME        = STANDING_FACILITIES_HEADER
      *           PARTITION_NAME    = 
      *           SUBPARTITION_NAME = 
      *           FILE_URI_LIST     = 
      *           ROWS_LOADED       = 
      *           LOGFILE_TABLE     = VALIDATE$3608_LOG
      *           BADFILE_TABLE     = VALIDATE$3608_BAD
      *           STATUS_TABLE      = 
      *           TEMPEXT_TABLE     = 
      *           CREDENTIAL_NAME   = 
      *           EXPIRATION_TIME   = 2025-05-22 10.08.24.436983000 EUROPE/BELGRADE
      *           --------------------------------
   **/
   FUNCTION GET_DET_USER_LOAD_OPERATIONS (
       pOperationId PLS_INTEGER
   ) RETURN VARCHAR2;

END;

/

CREATE OR REPLACE EDITIONABLE PACKAGE BODY "CT_MRDS"."FILE_MANAGER"
AS
  
   ----------------------------------------------------------------------------------------------------

--   FUNCTION GET_BUCKET_PATH(
--       pSourceFileConfigKey IN CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY%TYPE
--    )
--   RETURN VARCHAR2
--   IS
--     vBucketPath  VARCHAR2(400);
--     vParameters  CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
--   BEGIN
--      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileConfigKey => '||pSourceFileConfigKey));
--      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
--      SELECT A_SOURCE_KEY||'/'||SOURCE_FILE_ID||'/'||TABLE_ID||'/'
--        INTO vBucketPath
--        FROM CT_MRDS.A_SOURCE_FILE_CONFIG
--       WHERE A_SOURCE_FILE_CONFIG_KEY=pSourceFileConfigKey;
--      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);
--      RETURN vBucketPath;
--   EXCEPTION 
--      WHEN NO_DATA_FOUND THEN
--         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_NO_CONFIG_MATCH, 'ERROR', vParameters);
--         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_MATCH, ENV_MANAGER.MSG_NO_CONFIG_MATCH);
--   END GET_BUCKET_PATH;

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

--   FUNCTION GET_BUCKET_PATH(
--       pSourceKey             IN   CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_KEY%TYPE
--      ,pSourceFileId          IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID%TYPE 
--      ,pTableId               IN   CT_MRDS.A_SOURCE_FILE_CONFIG.TABLE_ID%TYPE
--      ,pParentFolder          IN   VARCHAR2 DEFAULT 'INBOX'
--    )
--   RETURN VARCHAR2
--   IS
--     vBucketPath  VARCHAR2(400);
--     vParameters  CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
--   BEGIN
--      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('   pSourceKey =>   '||nvl(to_char(pSourceKey, 'NULL')
--                                                           ,'pSourceFileId => '''||pSourceFileId||''''
--                                                           ,     'pTableId => '''||pTableId||''''
--                                                           ,'pParentFolder => '''||pParentFolder||''''
--                                                           ));
--      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
--      SELECT pParentFolder||'/'||A_SOURCE_KEY||'/'||SOURCE_FILE_ID||'/'||TABLE_ID||'/'
--        INTO vBucketPath
--        FROM CT_MRDS.A_SOURCE_FILE_CONFIG
--       WHERE A_SOURCE_KEY   = pSourceKey
--         AND SOURCE_FILE_ID = pSourceFileId
--         AND TABLE_ID       = pTableId;
--
--      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);
--      RETURN vBucketPath;
--   EXCEPTION 
--      WHEN NO_DATA_FOUND THEN
--         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_NO_CONFIG_MATCH, 'ERROR', vParameters);
--         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_MATCH, ENV_MANAGER.MSG_NO_CONFIG_MATCH);
--   END GET_BUCKET_PATH;

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

   FUNCTION GET_SOURCE_FILE_CONFIG(pFileUri               IN VARCHAR2 DEFAULT NULL
                                 , pSourceFileReceivedKey IN NUMBER   DEFAULT NULL
                                 , pSourceFileConfigKey   IN NUMBER   DEFAULT NULL)
   RETURN CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE
   IS
      vSourceFileConfig CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE;
      vParameters       CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST(              'pFileUri => '''||nvl(pFileUri,'NULL')||''''
                                                           ,'pSourceFileReceivedKey =>   '||nvl(to_char(pSourceFileReceivedKey),'NULL')
                                                             ,'pSourceFileConfigKey =>   '||nvl(to_char(pSourceFileConfigKey),'NULL')));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);

      BEGIN
         IF pFileUri IS NOT NULL THEN
            SELECT *
              INTO vSourceFileConfig
              FROM CT_MRDS.A_SOURCE_FILE_CONFIG
             WHERE REGEXP_LIKE(pFileUri, A_SOURCE_KEY||'/'||SOURCE_FILE_ID||'/'||TABLE_ID||'/'||SOURCE_FILE_NAME_PATTERN);
         ELSIF pSourceFileReceivedKey IS NOT NULL THEN
            SELECT T.*
              INTO vSourceFileConfig
              FROM CT_MRDS.A_SOURCE_FILE_CONFIG T, CT_MRDS.A_SOURCE_FILE_RECEIVED R
             WHERE T.A_SOURCE_FILE_CONFIG_KEY = R.A_SOURCE_FILE_CONFIG_KEY
               AND R.A_SOURCE_FILE_RECEIVED_KEY = pSourceFileReceivedKey;
         ELSIF pSourceFileConfigKey IS NOT NULL THEN
            SELECT *
              INTO vSourceFileConfig
              FROM CT_MRDS.A_SOURCE_FILE_CONFIG
             WHERE A_SOURCE_FILE_CONFIG_KEY = pSourceFileConfigKey;
         ELSE
            RAISE ENV_MANAGER.ERR_EMPTY_FILEURI_AND_RECKEY;
         END IF;
         -- Set global package variable vgSourceFileConfigKey - used in error messages
         vgSourceFileConfigKey := vSourceFileConfig.A_SOURCE_FILE_CONFIG_KEY;
      EXCEPTION 
         WHEN ENV_MANAGER.ERR_EMPTY_FILEURI_AND_RECKEY THEN
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_EMPTY_FILEURI_AND_RECKEY, 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_EMPTY_FILEURI_AND_RECKEY, ENV_MANAGER.MSG_EMPTY_FILEURI_AND_RECKEY);

         WHEN NO_DATA_FOUND THEN
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_NO_CONFIG_MATCH_FOR_FILEURI, 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_MATCH_FOR_FILEURI, ENV_MANAGER.MSG_NO_CONFIG_MATCH_FOR_FILEURI);

         WHEN TOO_MANY_ROWS THEN
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MULTIPLE_MATCH_FOR_SRCFILE, 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTIPLE_MATCH_FOR_SRCFILE, ENV_MANAGER.MSG_MULTIPLE_MATCH_FOR_SRCFILE);

         WHEN OTHERS THEN
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
            RAISE ENV_MANAGER.ERR_UNKNOWN;
      END;
      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);
      RETURN vSourceFileConfig;

   END GET_SOURCE_FILE_CONFIG;

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

   FUNCTION GET_SOURCE_FILE_RECEIVED_INFO(pSourceFileReceivedKey IN NUMBER DEFAULT NULL)
   --
   -- Get source file received info 
   --
   RETURN tSourceFileReceived
   IS
      vSourceFileReceived  tSourceFileReceived;
      vBucket              VARCHAR2(400);
      vParameters          CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedKey => '||nvl(to_char(pSourceFileReceivedKey),'NULL')));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      BEGIN
         SELECT R.A_SOURCE_FILE_RECEIVED_KEY, R.A_SOURCE_FILE_CONFIG_KEY, 
                      'INBOX'||'/'||T.A_SOURCE_KEY||'/'||T.SOURCE_FILE_ID||'/'||T.TABLE_ID||'/' as SOURCE_FILE_PREFIX_INBOX, 
                        'ODS'||'/'||T.A_SOURCE_KEY||'/'||T.TABLE_ID||'/'                        as SOURCE_FILE_PREFIX_ODS, 
                'QUARANTINE'||'/'||T.A_SOURCE_KEY||'/'||T.TABLE_ID||'/'                        as SOURCE_FILE_PREFIX_QUARANTINE, 
                    'ARCHIVE'||'/'||T.A_SOURCE_KEY||'/'||T.SOURCE_FILE_ID||'/'                  as SOURCE_FILE_PREFIX_ARCHIVE, 
                R.SOURCE_FILE_NAME, 
                R.RECEPTION_DATE, R.PROCESSING_STATUS, R.EXTERNAL_TABLE_NAME
           INTO vSourceFileReceived
           FROM CT_MRDS.A_SOURCE_FILE_RECEIVED R, CT_MRDS.A_SOURCE_FILE_CONFIG T
          WHERE R.A_SOURCE_FILE_CONFIG_KEY = T.A_SOURCE_FILE_CONFIG_KEY
            AND A_SOURCE_FILE_RECEIVED_KEY = pSourceFileReceivedKey;

--        vBucket := GET_BUCKET_PATH(pSourceFileConfigKey => vSourceFileReceived.A_SOURCE_FILE_CONFIG_KEY);
--        vSourceFileReceived.SOURCE_FILE_PREFIX_INBOX   :=   'INBOX/'||vBucket;
--        vSourceFileReceived.SOURCE_FILE_PREFIX_ODS     :=     'ODS/'||vBucket;
--        vSourceFileReceived.SOURCE_FILE_PREFIX_ARCHIVE := 'ARCHIVE/'||vBucket;

      EXCEPTION 
         WHEN NO_DATA_FOUND THEN
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_NO_CONFIG_FOR_RECEIVED_FILE, 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_FOR_RECEIVED_FILE, ENV_MANAGER.MSG_NO_CONFIG_FOR_RECEIVED_FILE);
         WHEN TOO_MANY_ROWS THEN
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MULTI_CONFIG_FOR_RECEIVED_FILE, 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTI_CONFIG_FOR_RECEIVED_FILE, ENV_MANAGER.MSG_MULTI_CONFIG_FOR_RECEIVED_FILE);
         WHEN OTHERS THEN
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));
      END;
      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);

      RETURN vSourceFileReceived;

   END GET_SOURCE_FILE_RECEIVED_INFO;

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

   FUNCTION  REGISTER_SOURCE_FILE_RECEIVED(pSourceFileReceivedName IN VARCHAR2)
   RETURN PLS_INTEGER
   --
   -- Register a newly received source file A_SOURCE_FILE_RECEIVED
   -- This overload automatically determines source file type from the file name
   --
   IS
      vSourceFileConfig       CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE;
      vSourceFileReceivedKey  PLS_INTEGER;
      vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedName => '''||nvl(pSourceFileReceivedName, 'NULL')||''''));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO',vParameters);

      vSourceFileConfig      := GET_SOURCE_FILE_CONFIG(pSourceFileReceivedName);
      vSourceFileReceivedKey := REGISTER_SOURCE_FILE_RECEIVED(pSourceFileReceivedName, vSourceFileConfig);
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);
      RETURN vSourceFileReceivedKey;
   EXCEPTION

      WHEN ENV_MANAGER.ERR_EMPTY_FILEURI_AND_RECKEY THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_EMPTY_FILEURI_AND_RECKEY, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_EMPTY_FILEURI_AND_RECKEY, ENV_MANAGER.MSG_EMPTY_FILEURI_AND_RECKEY);

      WHEN ENV_MANAGER.ERR_NO_CONFIG_MATCH_FOR_FILEURI THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_NO_CONFIG_MATCH_FOR_FILEURI, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_MATCH_FOR_FILEURI, ENV_MANAGER.MSG_NO_CONFIG_MATCH_FOR_FILEURI);

      WHEN ENV_MANAGER.ERR_FILE_NOT_EXISTS_ON_CLOUD THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_FILE_NOT_EXISTS_ON_CLOUD, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_NOT_EXISTS_ON_CLOUD, ENV_MANAGER.MSG_FILE_NOT_EXISTS_ON_CLOUD);

      WHEN ENV_MANAGER.ERR_FILE_ALREADY_REGISTERED THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_FILE_ALREADY_REGISTERED, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_ALREADY_REGISTERED, ENV_MANAGER.MSG_FILE_ALREADY_REGISTERED);

      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE ENV_MANAGER.ERR_UNKNOWN;
   END REGISTER_SOURCE_FILE_RECEIVED;

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

   FUNCTION REGISTER_SOURCE_FILE_RECEIVED(
       pSourceFileReceivedName IN VARCHAR2
      ,pSourceFileConfig       IN CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE)
   RETURN PLS_INTEGER
   --
   -- Register a newly received source file A_SOURCE_FILE_RECEIVED
   --
   IS
      vExternalTableName      VARCHAR2(200);
      vDirName                VARCHAR2(1000);
      vFileName               VARCHAR2(1000);
      vChecksum               A_SOURCE_FILE_RECEIVED.CHECKSUM%TYPE;
      vCreated                A_SOURCE_FILE_RECEIVED.CREATED%TYPE;
      vBytes                  A_SOURCE_FILE_RECEIVED.BYTES%TYPE;
      vSourceFileReceivedKey  PLS_INTEGER;
      vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
      vRow                    CT_MRDS.A_SOURCE_FILE_RECEIVED%ROWTYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedName => '''||nvl(pSourceFileReceivedName, 'NULL')||''''
                                                                 ,'pSourceFileConfig =>   '||'tSourceFileConfig record type'));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      vDirName := REGEXP_SUBSTR(pSourceFileReceivedName, '(.*/)(.*)', 1, 1, NULL, 1);
      --  Remove prefix from file name
      vFileName := REGEXP_SUBSTR(pSourceFileReceivedName,'[^/]*$');

      ENV_MANAGER.LOG_PROCESS_EVENT('gvCredentialName','DEBUG',ENV_MANAGER.gvCredentialName);
      ENV_MANAGER.LOG_PROCESS_EVENT('gvInboxBucketUri','DEBUG',ENV_MANAGER.gvInboxBucketUri);
      ENV_MANAGER.LOG_PROCESS_EVENT('vDirName','DEBUG',vDirName);

      SELECT 
         checksum,  created,  bytes
      INTO
         vChecksum, vCreated, vBytes
      FROM DBMS_CLOUD.LIST_OBJECTS(ENV_MANAGER.gvCredentialName, 
                                    ENV_MANAGER.gvInboxBucketUri || vDirName
                                  )
      WHERE object_name = vFileName
      ;
      vSourceFileReceivedKey := CT_MRDS.A_SOURCE_FILE_RECEIVED_KEY_SEQ.NEXTVAL;
      vExternalTableName := REPLACE(
                              REGEXP_SUBSTR(pSourceFileConfig.TEMPLATE_TABLE_NAME||'_'||vSourceFileReceivedKey,
                                            '\..*'),
                            '.','');

      INSERT INTO CT_MRDS.A_SOURCE_FILE_RECEIVED 
             (A_SOURCE_FILE_RECEIVED_KEY, A_SOURCE_FILE_CONFIG_KEY, 
              SOURCE_FILE_NAME, RECEPTION_DATE,
              PROCESSING_STATUS, EXTERNAL_TABLE_NAME,
              CHECKSUM, CREATED, BYTES)
      VALUES (vSourceFileReceivedKey, pSourceFileConfig.A_SOURCE_FILE_CONFIG_KEY, 
              vFileName, SYSDATE,
              'RECEIVED', vExternalTableName,
              vChecksum, vCreated, vBytes);
      COMMIT;

      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);
      RETURN vSourceFileReceivedKey;

   EXCEPTION
      WHEN NO_DATA_FOUND THEN
         ENV_MANAGER.MSG_FILE_NOT_EXISTS_ON_CLOUD := ENV_MANAGER.MSG_FILE_NOT_EXISTS_ON_CLOUD
                     ||cgBL||'           '||'File: '||ENV_MANAGER.gvInboxBucketUri || vDirName || vFileName;
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_FILE_NOT_EXISTS_ON_CLOUD, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_NOT_EXISTS_ON_CLOUD, ENV_MANAGER.MSG_FILE_NOT_EXISTS_ON_CLOUD);

      WHEN DUP_VAL_ON_INDEX THEN
         select * into vRow 
         from CT_MRDS.A_SOURCE_FILE_RECEIVED 
         where CHECKSUM = vChecksum 
           and CREATED = vCreated 
           and BYTES = vBytes
         ;
         ENV_MANAGER.MSG_FILE_ALREADY_REGISTERED := ENV_MANAGER.MSG_FILE_ALREADY_REGISTERED_C
                     ||cgBL||'           '||'Details about existing File: '
                     ||cgBL||'           '||'-------------------------'
                     ||cgBL||'           '||'A_SOURCE_FILE_RECEIVED_KEY = '||vRow.A_SOURCE_FILE_RECEIVED_KEY 
                     ||cgBL||'           '||'A_SOURCE_FILE_CONFIG_KEY   = '||vRow.A_SOURCE_FILE_CONFIG_KEY   
                     ||cgBL||'           '||'SOURCE_FILE_NAME           = '||vRow.SOURCE_FILE_NAME           
                     ||cgBL||'           '||'CHECKSUM                   = '||vRow.CHECKSUM                   
                     ||cgBL||'           '||'CREATED                    = '||vRow.CREATED                    
                     ||cgBL||'           '||'BYTES                      = '||vRow.BYTES                      
                     ||cgBL||'           '||'RECEPTION_DATE             = '||vRow.RECEPTION_DATE             
                     ||cgBL||'           '||'PROCESSING_STATUS          = '||vRow.PROCESSING_STATUS          
                     ||cgBL||'           '||'EXTERNAL_TABLE_NAME        = '||vRow.EXTERNAL_TABLE_NAME 
                     ||cgBL||'           '||'-------------------------'
                     ||cgBL||'           '||'There cannot be two files with the same values for (CHECKSUM, CREATED, BYTES)'
                     ;


--                     vChecksum, vCreated, vBytes
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_FILE_ALREADY_REGISTERED, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_ALREADY_REGISTERED, ENV_MANAGER.MSG_FILE_ALREADY_REGISTERED);

      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));

   END REGISTER_SOURCE_FILE_RECEIVED;

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

   PROCEDURE SET_SOURCE_FILE_RECEIVED_STATUS(pSourceFileReceivedKey IN PLS_INTEGER, pStatus IN VARCHAR2)
   --
   -- Change status of file in the A_SOURCE_FILE_RECEIVED table
   --
   IS
      vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedKey =>   '||nvl(to_char(pSourceFileReceivedKey),'NULL')
                                                                          ,'pStatus => '''||nvl(pStatus, 'NULL')||''''));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      UPDATE CT_MRDS.A_SOURCE_FILE_RECEIVED 
         SET PROCESSING_STATUS=pStatus 
       WHERE A_SOURCE_FILE_RECEIVED_KEY=pSourceFileReceivedKey;
      COMMIT;
      ENV_MANAGER.LOG_PROCESS_EVENT('File status changed to '||pStatus,'INFO', vParameters);
      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);

   EXCEPTION
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE ENV_MANAGER.ERR_UNKNOWN;

   END SET_SOURCE_FILE_RECEIVED_STATUS;

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

   FUNCTION GET_EXTERNAL_TABLE_COLUMNS(pTargetTableTemplate IN VARCHAR2)
   RETURN CLOB
   --
   -- Create list of columns for DBMS_CLOUD.CREATE_EXTERNAL_TABLE from existing template table
   --
   IS
      vColumnList CLOB;
      vTableName VARCHAR2(200);
      vSchemaName VARCHAR2(200);
   BEGIN
      vSchemaName := REPLACE(REGEXP_SUBSTR(pTargetTableTemplate,'.*\.'),'.','');
      vTableName := REPLACE(REGEXP_SUBSTR(pTargetTableTemplate,'\..*'),'.','');
      DBMS_METADATA.SET_TRANSFORM_PARAM(-1, 'SQLTERMINATOR', True);
      DBMS_METADATA.SET_TRANSFORM_PARAM(-1, 'COLLATION_CLAUSE', 'NEVER'); 
      DBMS_METADATA.SET_TRANSFORM_PARAM(-1, 'REF_CONSTRAINTS', False); 
      DBMS_METADATA.SET_TRANSFORM_PARAM(-1, 'STORAGE', False); 
      DBMS_METADATA.SET_TRANSFORM_PARAM(-1, 'TABLESPACE', False); 
      DBMS_METADATA.SET_TRANSFORM_PARAM(-1, 'SEGMENT_ATTRIBUTES', False); 
      vColumnList := RTRIM( 
                       LTRIM(
                          REGEXP_SUBSTR(DBMS_METADATA.GET_DDL('TABLE', vTableName, vSchemaName),'\(.*\)',1,1,'mn'),
                       '('), 
                    ')');
      RETURN vColumnList;
   END GET_EXTERNAL_TABLE_COLUMNS;

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

   PROCEDURE CREATE_EXTERNAL_PART_TABLE (
      pTableName          IN VARCHAR2,
      pTemplateTableName  IN VARCHAR2,
      pPrefix             IN VARCHAR2,
      pFileName           IN VARCHAR2 DEFAULT NULL,
      pDelimiter          IN VARCHAR2 DEFAULT ',',
      pBucketUri          IN VARCHAR2 DEFAULT ENV_MANAGER.gvInboxBucketUri
   )
   --
   -- Create external table for historised data
   --
   IS
      vTableName     VARCHAR2(200);
      vColumnList    CLOB;
      vFieldList     CLOB;
      vFormat        VARCHAR2(200);

      vPrefix        VARCHAR2(200);
      vFileName      VARCHAR2(1000);
      vFileExtension VARCHAR2(200);
      vPartitioningClause VARCHAR2(400);
      vMinDate       TIMESTAMP := TO_TIMESTAMP('2024-12-01','YYYY-MM-DD');
      vParameters    CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST(        'pTableName => '''||nvl(pTableName, 'NULL')||''
                                                           ,'pTemplateTableName => '''||nvl(pTemplateTableName, 'NULL')||''
                                                                      ,'pPrefix => '''||nvl(pPrefix, 'NULL')||''
                                                                    ,'pFileName => '''||nvl(pFileName, 'NULL')||''
                                                                   ,'pDelimiter => '''||nvl(pDelimiter, 'NULL')||''
                                                                   ,'pBucketUri => '''||nvl(pBucketUri, 'NULL')||''
                                                           ));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      -- Strip off leading and trailing slashes from prefix
      vPrefix := TRIM(BOTH '/' FROM pPrefix);

      -- Generate column and field list from template table
      GENERATE_EXTERNAL_TABLE_PARAMS (pTemplateTableName, vColumnList, vFieldList);

--      dbms_output.put_line(vFieldList);
      -- For INBOX tables use csv, for archive tables parquet + implicit partitioning
      IF SUBSTR(pPrefix,1,5) = 'INBOX' OR SUBSTR(pPrefix,1,3) = 'ODS' 
         OR SUBSTR(pPrefix,1,7) = 'ARCHIVE'
      THEN
         IF pDelimiter = '|' THEN
            vFormat := json_object('delimiter' VALUE '|', 'skipheaders' VALUE '1');
         ELSE
            vFormat := json_object('type' VALUE 'CSV', 'skipheaders' VALUE '1', 'ignoremissingcolumns' value 'true');
         END IF;
         vFileExtension := '.csv';

      ELSIF SUBSTR(pPrefix,1,10) = 'HISTORISED' THEN
--         vFormat     := '{"type":"parquet","implicit_partition_columns":["year","month"]}';
         vFormat := json_object('type' VALUE 'parquet', 'schema' VALUE 'first');
         vColumnList :=  NULL;
         vFieldList := NULL;
--         vFileExtension := '.parquet';
--      ELSIF SUBSTR(pPrefix,1,7) = 'ARCHIVE' THEN
--         vFormat     := '{"type":"parquet","implicit_partition_columns":["year","month"]}';
--         vColumnList :=  vColumnList||' , "year" number, "month" number';
--         vFileExtension := '.parquet';

      ELSE
         ENV_MANAGER.MSG_UNKNOWN_PREFIX := ENV_MANAGER.MSG_UNKNOWN_PREFIX ||': '||pPrefix;
         RAISE ENV_MANAGER.ERR_UNKNOWN_PREFIX;
      END IF;

      --
      vFormat := json_object('type' value 'parquet', 'schema' value 'first');

      -- No filename give: Match all csv files
      IF pFileName IS NOT NULL THEN
         vFileName := pFileName;
      ELSE
         vFileName := pBucketUri||vPrefix||'/*'||vFileExtension;
      END IF;

      ENV_MANAGER.LOG_PROCESS_EVENT('pTableName',        'DEBUG', pTableName);
      ENV_MANAGER.LOG_PROCESS_EVENT('ENV_MANAGER.vpCredentialName',  'DEBUG', ENV_MANAGER.gvCredentialName);
      ENV_MANAGER.LOG_PROCESS_EVENT('vFileName',         'DEBUG', vFileName);
      ENV_MANAGER.LOG_PROCESS_EVENT('vColumnList',       'DEBUG', vColumnList);
      ENV_MANAGER.LOG_PROCESS_EVENT('vFieldList',        'DEBUG', vFieldList);
      ENV_MANAGER.LOG_PROCESS_EVENT('vFormat',           'DEBUG', vFormat);



--      dbms_output.put_line('DBMS_CLOUD.CREATE_EXTERNAL_TABLE, TABLE_NAME => '|| pTableName || 'CREDENTIAL_NAME => OCI$RESOURCE_PRINCIPAL, FILE_URI_LIST => '|| vFileName || ' COLUMN_LIST =>  ' || vColumnList ||',FIELD_LIST => '||  vFieldList || ' FORMAT => '|| vFormat ||')');
--      DBMS_CLOUD.CREATE_EXTERNAL_TABLE(
--         TABLE_NAME => pTableName,
--         CREDENTIAL_NAME => ENV_MANAGER.vpCredentialName,
--         FILE_URI_LIST => vFileName,
--         COLUMN_LIST =>  vColumnList,
--         FIELD_LIST =>  vFieldList,
--         FORMAT => vFormat
--      );

      vColumnList := vColumnList ||cgBL||'"WORKFLOW_START"          TIMESTAMP';
--      vPartName := 'p'||TO_CHAR(vMinDate, 'yyyymm');
      vPartitioningClause := 'partition by range (WORKFLOW_START) 
            (
               PARTITION p202412     VALUES LESS THAN (TO_DATE(''01-01-2025'', ''DD-MM-YYYY'')) location ( ''https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/frcnomajoc7v/b/mrds_history_tst/o/LM/STANDING_FACILITIES_HEADER/YEAR=2024/MONTH=12/*.parquet''),
               PARTITION p202501     VALUES LESS THAN (TO_DATE(''01-02-2025'', ''DD-MM-YYYY'')) location ( ''https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/frcnomajoc7v/b/mrds_history_tst/o/LM/STANDING_FACILITIES_HEADER/YEAR=2025/MONTH=01/*.parquet'')
            )';

      DBMS_CLOUD.CREATE_EXTERNAL_PART_TABLE(
         table_name =>pTableName,  
         credential_name => ENV_MANAGER.gvCredentialName,
         format => vFormat,
         column_list => vColumnList,
         partitioning_clause => vPartitioningClause
      );






      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);

   EXCEPTION
      WHEN ENV_MANAGER.ERR_UNKNOWN_PREFIX THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN_PREFIX, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN_PREFIX, ENV_MANAGER.MSG_UNKNOWN_PREFIX);
      WHEN ENV_MANAGER.ERR_MISSING_COLUMN_DATE_FORMAT THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT, ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT);
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));

   END CREATE_EXTERNAL_PART_TABLE;

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

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

   PROCEDURE CREATE_EXTERNAL_TABLE (
      pTableName          IN VARCHAR2,
      pTemplateTableName  IN VARCHAR2,
      pPrefix             IN VARCHAR2,
      pBucketUri          IN VARCHAR2 DEFAULT ENV_MANAGER.gvInboxBucketUri,
      pFileName           IN VARCHAR2 DEFAULT NULL,
      pDelimiter          IN VARCHAR2 DEFAULT ','
   )
   --
   -- Create external table for a single source file to validate the file structure
   --
   IS
      vTableName     VARCHAR2(200);
      vColumnList    CLOB;
      vFieldList     CLOB;
      vFormat        VARCHAR2(200);

      vPrefix        VARCHAR2(200);
      vFileName      VARCHAR2(1000);
      vFileExtension VARCHAR2(200);
      vParameters    CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST(        'pTableName => '''||nvl(pTableName, 'NULL')||''''
                                                           ,'pTemplateTableName => '''||nvl(pTemplateTableName, 'NULL')||''''
                                                                      ,'pPrefix => '''||nvl(pPrefix, 'NULL')||''''
                                                                    ,'pFileName => '''||nvl(pFileName, 'NULL')||''''
                                                                   ,'pDelimiter => '''||nvl(pDelimiter, 'NULL')||''''
                                                                   ,'pBucketUri => '''||nvl(pBucketUri, 'NULL')||''''
                                                           ));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      -- Strip off leading and trailing slashes from prefix
      vPrefix := TRIM(BOTH '/' FROM pPrefix);

      -- Generate column and field list from template table
      GENERATE_EXTERNAL_TABLE_PARAMS (pTemplateTableName, vColumnList, vFieldList);

--      dbms_output.put_line(vFieldList);



      --vFormat evaluation based on pPrefix or pBucketUri value
      -- For INBOX tables use csv, for archive tables parquet + implicit partitioning
      IF SUBSTR(pPrefix,1,5) = 'INBOX' OR SUBSTR(pPrefix,1,3) = 'ODS' 
         OR SUBSTR(pPrefix,1,7) = 'ARCHIVE'
      THEN
         IF pDelimiter = '|' THEN
            vFormat := json_object('delimiter'        VALUE '|'
                                 , 'skipheaders'      VALUE '1');
         ELSE
            vFormat := json_object('type'                   VALUE 'CSV'
                                 , 'skipheaders'            VALUE '1'
                                 , 'ignoremissingcolumns'   value 'true');
         END IF;
         vFileExtension := '.csv';

--      ELSIF SUBSTR(pPrefix,1,10) = 'HISTORISED' THEN
--         vFormat     := '{"type":                       "parquet"
--                         ,"implicit_partition_type":    "hive"
--                         ,"implicit_partition_columns":["year","month"]}';
----         vFormat := json_object('type' VALUE 'parquet', 'schema' VALUE 'first');
--         vColumnList :=  NULL;
--         vFieldList := NULL;
--         vFileExtension := '.parquet';


--      ELSIF SUBSTR(pPrefix,1,7) = 'ARCHIVE' THEN
--         vFormat     := '{"type":"parquet","implicit_partition_columns":["year","month"]}';
--         vColumnList :=  vColumnList||' , "year" number, "month" number';
--         vFileExtension := '.parquet';

      ELSIF INSTR(pBucketUri, ENV_MANAGER.gvHistoryBucketName)>0 THEN
         vFormat     := '{"type":                       "parquet"
                         ,"implicit_partition_type":    "hive"
                         ,"implicit_partition_columns":["YEAR","MONTH"]}';
         vColumnList :=  vColumnList||cgBL||' , "YEAR"    varchar2(4)'||cgBL||', "MONTH" varchar2(2)';
         vFieldList := NULL;
         vFileExtension := '.parquet';


      ELSE
         ENV_MANAGER.MSG_UNKNOWN_PREFIX := ENV_MANAGER.MSG_UNKNOWN_PREFIX ||': '||pPrefix;
         RAISE ENV_MANAGER.ERR_UNKNOWN_PREFIX;
      END IF;

      -- No filename give: Match all csv files
      IF pFileName IS NOT NULL THEN
         vFileName := pFileName;
      ELSE
         vFileName := pBucketUri||vPrefix||'/*'||vFileExtension;
      END IF;

      ENV_MANAGER.LOG_PROCESS_EVENT('pTableName',        'DEBUG', pTableName);
      ENV_MANAGER.LOG_PROCESS_EVENT('ENV_MANAGER.vpCredentialName',  'DEBUG', ENV_MANAGER.gvCredentialName);
      ENV_MANAGER.LOG_PROCESS_EVENT('vFileName',         'DEBUG', vFileName);
      ENV_MANAGER.LOG_PROCESS_EVENT('vColumnList',       'DEBUG', vColumnList);
      ENV_MANAGER.LOG_PROCESS_EVENT('vFieldList',        'DEBUG', vFieldList);
      ENV_MANAGER.LOG_PROCESS_EVENT('vFormat',           'DEBUG', vFormat);

--      dbms_output.put_line('DBMS_CLOUD.CREATE_EXTERNAL_TABLE, TABLE_NAME => '|| pTableName || 'CREDENTIAL_NAME => OCI$RESOURCE_PRINCIPAL, FILE_URI_LIST => '|| vFileName || ' COLUMN_LIST =>  ' || vColumnList ||',FIELD_LIST => '||  vFieldList || ' FORMAT => '|| vFormat ||')');
      DBMS_CLOUD.CREATE_EXTERNAL_TABLE(
         TABLE_NAME => pTableName,
         CREDENTIAL_NAME => ENV_MANAGER.gvCredentialName,
         FILE_URI_LIST => vFileName,
         COLUMN_LIST =>  vColumnList,
         FIELD_LIST =>  vFieldList,
         FORMAT => vFormat
      );

--      DBMS_CLOUD.CREATE_EXTERNAL_TABLE(
--         table_name =>'LM_STANDING_FACILITIES_HEADER_HIST_v03',  
--         credential_name => 'OCI$RESOURCE_PRINCIPAL',
--         file_uri_list => 'https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/frcnomajoc7v/b/mrds_history_tst/o/LM/STANDING_FACILITIES_HEADER/*.parquet',
--         format            => '{"type":"parquet",
--                             "implicit_partition_type":"hive",
--                             "implicit_partition_columns":["year","month"]}',      
--         column_list => ...
--         );

      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);

   EXCEPTION
      WHEN ENV_MANAGER.ERR_UNKNOWN_PREFIX THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN_PREFIX, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN_PREFIX, ENV_MANAGER.MSG_UNKNOWN_PREFIX);
      WHEN ENV_MANAGER.ERR_MISSING_COLUMN_DATE_FORMAT THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT, ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT);
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));

   END CREATE_EXTERNAL_TABLE;

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

   PROCEDURE CREATE_EXTERNAL_TABLE(pSourceFileReceivedKey IN NUMBER)
   --
   -- Create external table for a single source file to validate the file structure
   --
   IS
      vSourceFileConfig    CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE; 
      vSourceFileReceived  tSourceFileReceived; 
      vTableName           VARCHAR2(200);
      vFileName            VARCHAR2(1000);
      vParameters          CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedKey => '||nvl(to_char(pSourceFileReceivedKey), 'NULL')));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);

      vSourceFileConfig   := GET_SOURCE_FILE_CONFIG(pSourceFileReceivedKey => pSourceFileReceivedKey);
      vSourceFileReceived := GET_SOURCE_FILE_RECEIVED_INFO(pSourceFileReceivedKey);
      vTableName          := vSourceFileConfig.TEMPLATE_TABLE_NAME;

      vFileName  := ENV_MANAGER.gvInboxBucketUri ||vSourceFileReceived.SOURCE_FILE_PREFIX_INBOX||vSourceFileReceived.SOURCE_FILE_NAME;

      CREATE_EXTERNAL_TABLE(
         pTableName => vSourceFileReceived.EXTERNAL_TABLE_NAME,
         pTemplateTableName => vSourceFileConfig.TEMPLATE_TABLE_NAME,
         pPrefix => vSourceFileReceived.SOURCE_FILE_PREFIX_INBOX,
         pBucketUri => ENV_MANAGER.gvInboxBucketUri,
         pFileName => vFileName,
         pDelimiter => ','
        );
      --DBMS_CLOUD.CREATE_EXTERNAL_TABLE(
         --TABLE_NAME => vSourceFileReceived.EXTERNAL_TABLE_NAME,
         --CREDENTIAL_NAME => ENV_MANAGER.vpCredentialName,
         --FILE_URI_LIST => ENV_MANAGER.vpInboxBucketUri ||vSourceFileReceived.SOURCE_FILE_PREFIX_INBOX||vSourceFileReceived.SOURCE_FILE_NAME,
         --COLUMN_LIST =>  GET_EXTERNAL_TABLE_COLUMNS(vSourceFileConfig.TEMPLATE_TABLE_NAME),
         --FORMAT => json_object('type' VALUE 'CSV', 'skipheaders' VALUE '1')
      --);
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);

   END CREATE_EXTERNAL_TABLE;

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

   PROCEDURE VALIDATE_SOURCE_FILE_RECEIVED(pSourceFileReceivedKey IN NUMBER)
   --
   -- Check the structure of the received file using DBMS_CLOUD.VALIDATE_EXTERNAL_TABLE
   --
   IS
      vSourceFileReceived  tSourceFileReceived; 
      vOperationId         NUMBER := -1;
      vBadfileTable        USER_LOAD_OPERATIONS.BADFILE_TABLE%TYPE;
      vStatus              USER_LOAD_OPERATIONS.STATUS%TYPE;
      vErrors              NUMBER := 0;
      vNumRows             NUMBER := 0;
      vParameters          CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedKey => '||nvl(to_char(pSourceFileReceivedKey), 'NULL')));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);
      vSourceFileReceived := GET_SOURCE_FILE_RECEIVED_INFO(pSourceFileReceivedKey);
      ENV_MANAGER.LOG_PROCESS_EVENT('vSourceFileReceived.EXTERNAL_TABLE_NAME: '||vSourceFileReceived.EXTERNAL_TABLE_NAME,'DEBUG', vParameters); 
      BEGIN
         DBMS_CLOUD.VALIDATE_EXTERNAL_TABLE(vSourceFileReceived.EXTERNAL_TABLE_NAME, vOperationId);
      EXCEPTION
         WHEN OTHERS THEN
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_FILE_VALIDATION_FAILED_C, 'ERROR', vParameters);
--            SET_SOURCE_FILE_RECEIVED_STATUS(pSourceFileReceivedKey => pSourceFileReceivedKey, pStatus => 'VALIDATION_FAILED');
            MOVE_FILE(pSourceFileReceivedKey => pSourceFileReceivedKey, pDestination => 'QUARANTINE');
            RAISE;
      END;
      ENV_MANAGER.LOG_PROCESS_EVENT('vOperationId of validation: '||vOperationId,'DEBUG', vParameters);
      IF vOperationId = -1
      THEN
         RAISE ENV_MANAGER.ERR_DIDNT_GET_LOAD_OPERATION_ID;
      END IF;

      SELECT BADFILE_TABLE, ROWS_LOADED, STATUS
        INTO vBadfileTable, vNumRows, vStatus
        FROM USER_LOAD_OPERATIONS
       WHERE ID = vOperationId;

--      DBMS_OUTPUT.PUT_LINE(vStatus);
      SET_SOURCE_FILE_RECEIVED_STATUS(pSourceFileReceivedKey => pSourceFileReceivedKey, pStatus => 'VALIDATED');
      ENV_MANAGER.LOG_PROCESS_EVENT('File status changed to VALIDATED','DEBUG', vParameters);
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);

   EXCEPTION
      WHEN ENV_MANAGER.ERR_DIDNT_GET_LOAD_OPERATION_ID THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_DIDNT_GET_LOAD_OPERATION_ID, 'ERROR', vParameters);
         SET_SOURCE_FILE_RECEIVED_STATUS(pSourceFileReceivedKey => pSourceFileReceivedKey, pStatus => 'VALIDATION_FAILED');
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_DIDNT_GET_LOAD_OPERATION_ID, ENV_MANAGER.MSG_DIDNT_GET_LOAD_OPERATION_ID);

      WHEN OTHERS THEN
         IF SQLCODE = -20404 THEN
            ENV_MANAGER.MSG_FILE_NOT_FOUND_ON_CLOUD := ENV_MANAGER.MSG_FILE_NOT_FOUND_ON_CLOUD_C||cgBL||SQLERRM;
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_FILE_NOT_FOUND_ON_CLOUD, 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_NOT_FOUND_ON_CLOUD, ENV_MANAGER.MSG_FILE_NOT_FOUND_ON_CLOUD);

         ELSIF SQLCODE = -20003 THEN
            execute immediate 'select LISTAGG(record, CHR(13)||CHR(10)) from (select * from '||REGEXP_SUBSTR(SQLERRM, '"([^"]+)"."([^"]+)"')||' order by rownum desc) where rownum <=2'
            into vgMsgTmp;
            ENV_MANAGER.MSG_FILE_VALIDATION_FAILED := ENV_MANAGER.MSG_FILE_VALIDATION_FAILED_C||cgBL||SQLERRM||cgBL||vgMsgTmp;
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_FILE_VALIDATION_FAILED, 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_VALIDATION_FAILED, ENV_MANAGER.MSG_FILE_VALIDATION_FAILED);
--         ELSIF SQLCODE = -20000 THEN
            -- TO_DO  Add additional info about current config
            -- ENV_MANAGER.MSG_FILE_VALIDATION_FAILED := ENV_MANAGER.MSG_FILE_VALIDATION_FAILED_C||cgBL||SQLERRM||cgBL||FILE_MANAGER.OUTPUT_SOURCE_FILE_CONFIG_INFO( ..config key value.. );
--            dbms_output.put_line(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));
--            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_WRONG_DATE_TIMESTAMP_FORMAT, 'ERROR', vParameters);
--            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
--            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_WRONG_DATE_TIMESTAMP_FORMAT, ENV_MANAGER.MSG_WRONG_DATE_TIMESTAMP_FORMAT);

         ELSE
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE, pSourceFileReceivedKey=>pSourceFileReceivedKey), 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE, pSourceFileReceivedKey=>pSourceFileReceivedKey));
         END IF;
   END VALIDATE_SOURCE_FILE_RECEIVED;

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

   FUNCTION VALIDATE_EXTERNAL_TABLE(pTableName IN VARCHAR2)
   RETURN VARCHAR2
   --
   -- wrapper for DBMS_CLOUD.VALIDATE_EXTERNAL_TABLE
   --
   IS
      vOperationId         NUMBER := -1;
      vBadfileTable        USER_LOAD_OPERATIONS.BADFILE_TABLE%TYPE;
      vLogfileTable        USER_LOAD_OPERATIONS.LOGFILE_TABLE%TYPE;
      vStatus              USER_LOAD_OPERATIONS.STATUS%TYPE;
      vParameters          CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
      vDetails clob;
      TYPE TCURSOR is REF CURSOR;
      vCursor TCURSOR;
      vQuery VARCHAR2(1000);
      vRecord VARCHAR2(10000);
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pTableName => '''||nvl(pTableName, 'NULL')||''''));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      DBMS_CLOUD.VALIDATE_EXTERNAL_TABLE(pTableName, vOperationId);
      ENV_MANAGER.LOG_PROCESS_EVENT('vOperationId of validation: '||vOperationId,'DEBUG', vParameters);
      IF vOperationId = -1
      THEN
         RAISE ENV_MANAGER.ERR_DIDNT_GET_LOAD_OPERATION_ID;
      END IF;

      SELECT decode(STATUS, 'COMPLETED', 'PASSED', STATUS), LOGFILE_TABLE, BADFILE_TABLE
        INTO vStatus, vLogfileTable, vBadfileTable
        FROM USER_LOAD_OPERATIONS
       WHERE ID = vOperationId;

   RETURN vStatus;
   EXCEPTION
      WHEN ENV_MANAGER.ERR_DIDNT_GET_LOAD_OPERATION_ID THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_DIDNT_GET_LOAD_OPERATION_ID, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_DIDNT_GET_LOAD_OPERATION_ID, ENV_MANAGER.MSG_DIDNT_GET_LOAD_OPERATION_ID);

      WHEN OTHERS THEN
         SELECT decode(STATUS, 'COMPLETED', 'PASSED', STATUS), LOGFILE_TABLE, BADFILE_TABLE
           INTO vStatus, vLogfileTable, vBadfileTable
           FROM USER_LOAD_OPERATIONS
          WHERE ID = vOperationId;
         vQuery := 'select record from (
                                 select
                                     nvl(l.record,''----------------------------------------------------'') as record
                                    ,rownum as lp
                                    ,max(case when nvl(instr(l.record, ''error'' ),0) > 0 then rownum else 0 end) over (partition by 1) as ENV_MANAGER.ERR_row
                                 from '||vLogfileTable||' l 
                                 )
                              where lp >= ENV_MANAGER.ERR_row
                              order by rownum';

         vDetails := vStatus||cgBL||'----------------------------------------------------'||cgBL;

         OPEN vCursor for vQuery;
         loop
            fetch vCursor into vRecord;
            EXIT WHEN vCursor%NOTFOUND;
            vDetails := vDetails ||vRecord ||cgBL;
--         for i in  loop
--            vDetails := vDetails ||i.record ||cgBL;
         end loop;
         CLOSE vCursor;
         vDetails := vDetails||'More details can be found in below tables:'||cgBL||
         '  SELECT * FROM USER_LOAD_OPERATIONS WHERE ID = '||vOperationId||';'||cgBL||
         '  SELECT * FROM '||vLogfileTable||';'||cgBL||
         '  SELECT * FROM '||vBadfileTable||';'
         ;

         RETURN vDetails;

   END VALIDATE_EXTERNAL_TABLE;

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

   FUNCTION S_VALIDATE_EXTERNAL_TABLE(pTableName IN VARCHAR2)
   RETURN VARCHAR2
   --
   -- Simple
   --
   IS
      vCount PLS_INTEGER;
   BEGIN
      execute immediate 'select count(1) from '||pTableName into vCount;
      IF vCount >= 0
      THEN
         RETURN 'PASSED';
      END IF;

   RETURN 'FAILED';
   EXCEPTION
      WHEN OTHERS THEN
         RETURN 'FAILED';
   END S_VALIDATE_EXTERNAL_TABLE;

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

   PROCEDURE DROP_EXTERNAL_TABLE(pSourceFileReceivedKey IN NUMBER)
   --
   -- Drop external table created to validate the file structure
   --
   IS
      vSourceFileReceived tSourceFileReceived; 
      vParameters         CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
	   vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedKey => '||nvl(to_char(pSourceFileReceivedKey), 'NULL')));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);
      vSourceFileReceived := GET_SOURCE_FILE_RECEIVED_INFO(pSourceFileReceivedKey);
      EXECUTE IMMEDIATE 'DROP TABLE '||vSourceFileReceived.EXTERNAL_TABLE_NAME;

      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);
   EXCEPTION
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));
   END DROP_EXTERNAL_TABLE;

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

   PROCEDURE COPY_FILE(pSourceFileReceivedKey IN NUMBER, pDestination IN VARCHAR2)
   -- 
   -- Possible pDestination values are: 'ODS' or 'ARCHIVE'
   --
   IS
      vSourceFileReceivedInfo tSourceFileReceived; 
      vSourceObject           VARCHAR2(2000);
      vTargetObject           VARCHAR2(2000);
      vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
--      vStatus                 VARCHAR2(20);
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedKey => '  ||nvl(to_char(pSourceFileReceivedKey), 'NULL'),
                                                                      'pDestination => '''||nvl(pDestination, 'NULL')||''''));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);

      vSourceFileReceivedInfo := GET_SOURCE_FILE_RECEIVED_INFO(pSourceFileReceivedKey); 

      IF pDestination = 'ODS' THEN
         vSourceObject := ENV_MANAGER.gvInboxBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_INBOX  ||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
         vTargetObject := ENV_MANAGER.gvDataBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_ODS    ||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
--         vStatus       := 'READY_FOR_INGESTION';
--      ELSIF pDestination = 'ARCHIVE' THEN
--         vSourceObject := ENV_MANAGER.vpInboxBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_ODS    ||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
--         vTargetObject := ENV_MANAGER.vpDataBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_ARCHIVE||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
--         vStatus       := 'ARCHIVED';
      ELSE
         RAISE ENV_MANAGER.ERR_WRONG_DESTINATION_PARAM;
      END IF;

      DBMS_CLOUD.COPY_OBJECT(source_credential_name => ENV_MANAGER.gvCredentialName, 
                             source_object_uri      => vSourceObject,
                             target_object_uri      => vTargetObject,
                             target_credential_name => ENV_MANAGER.gvCredentialName
                            );
      ENV_MANAGER.LOG_PROCESS_EVENT('File copied to '||pDestination||' target location','DEBUG', vTargetObject);
--      ENV_MANAGER.LOG_PROCESS_EVENT('File copied to '||pTarget||' target location','DEBUG', vTargetObject);

--      SET_SOURCE_FILE_RECEIVED_STATUS(pSourceFileReceivedKey => pSourceFileReceivedKey, pStatus => vStatus);
--      ENV_MANAGER.LOG_PROCESS_EVENT('File status changed to '||vStatus,'DEBUG', vParameters);
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);

   EXCEPTION
--      WHEN ENV_MANAGER.ERR_WRONG_DESTINATION_PARAM THEN
--         ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM := ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM
--                     ||cgBL||'           '||'Possible parameters are: ''ODS'' or ''ARCHIVE'''
--                     ||cgBL||'           '||'Provided destination parameter: '''||pTarget||'''';
--         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM, 'ERROR', vParameters);
--         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_WRONG_DESTINATION_PARAM, ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM);
--      WHEN ENV_MANAGER.ERR_NO_CONFIG_FOR_RECEIVED_FILE THEN 
--         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_NO_CONFIG_FOR_RECEIVED_FILE, 'ERROR', vParameters);
--         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_FOR_RECEIVED_FILE, ENV_MANAGER.MSG_NO_CONFIG_FOR_RECEIVED_FILE);
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE ENV_MANAGER.ERR_UNKNOWN;
   END COPY_FILE;

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

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

   PROCEDURE MOVE_FILE(pSourceFileReceivedKey IN NUMBER, pDestination IN VARCHAR2)
   -- 
   -- Possible pDestination values are: 'ODS' or 'ARCHIVE'
   --
   IS
      vSourceFileReceivedInfo tSourceFileReceived; 
      vSourceObject           VARCHAR2(2000);
      vTargetObject           VARCHAR2(2000);
      vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
      vStatus                 VARCHAR2(20);
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedKey => '  ||nvl(to_char(pSourceFileReceivedKey), 'NULL'),
                                                                      'pDestination => '''||nvl(pDestination, 'NULL')||''''));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);


      vSourceFileReceivedInfo := GET_SOURCE_FILE_RECEIVED_INFO(pSourceFileReceivedKey); 

      IF    pDestination   = 'ODS' THEN
            vSourceObject :=  ENV_MANAGER.gvInboxBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_INBOX  ||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
            vTargetObject :=  ENV_MANAGER.gvDataBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_ODS    ||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
            vStatus       := 'READY_FOR_INGESTION';
      ELSIF pDestination   = 'QUARANTINE' THEN
         vSourceObject    :=  ENV_MANAGER.gvInboxBucketUri ||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_INBOX     ||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
         vTargetObject    :=  ENV_MANAGER.gvInboxBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_QUARANTINE||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
         vStatus          := 'VALIDATION_FAILED';

--      ELSIF pDestination = 'ARCHIVE' THEN
--         vSourceObject := ENV_MANAGER.vpInboxBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_INBOX  ||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
--         vTargetObject := ENV_MANAGER.vpInboxBucketUri||vSourceFileReceivedInfo.SOURCE_FILE_PREFIX_ARCHIVE||vSourceFileReceivedInfo.SOURCE_FILE_NAME;
--         vStatus       := 'ARCHIVED';
--         vStatus       := 'READY_FOR_INGESTION';
      ELSE
         RAISE ENV_MANAGER.ERR_WRONG_DESTINATION_PARAM;
      END IF;

      DBMS_CLOUD.MOVE_OBJECT(source_credential_name => ENV_MANAGER.gvCredentialName, 
                             source_object_uri      => vSourceObject,
                             target_object_uri      => vTargetObject,
                             target_credential_name => ENV_MANAGER.gvCredentialName
                            );
      ENV_MANAGER.LOG_PROCESS_EVENT('File moved to '||pDestination||' target location','DEBUG', vTargetObject);
      SET_SOURCE_FILE_RECEIVED_STATUS(pSourceFileReceivedKey => pSourceFileReceivedKey, pStatus => vStatus);
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);

   EXCEPTION
      WHEN ENV_MANAGER.ERR_WRONG_DESTINATION_PARAM THEN
         ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM := ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM
                     ||cgBL||'           '||'Possible parameters are: ''ODS'' or ''ARCHIVE'''
                     ||cgBL||'           '||'Provided destination parameter: '''||pDestination||'''';
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_WRONG_DESTINATION_PARAM, ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM);
      WHEN ENV_MANAGER.ERR_NO_CONFIG_FOR_RECEIVED_FILE THEN 
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_NO_CONFIG_FOR_RECEIVED_FILE, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_FOR_RECEIVED_FILE, ENV_MANAGER.MSG_NO_CONFIG_FOR_RECEIVED_FILE);
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE ENV_MANAGER.ERR_UNKNOWN;
   END MOVE_FILE;

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

   PROCEDURE DELETE_FOLDER_CONTENTS(pBucketName IN VARCHAR2, pFolderPrefix IN VARCHAR2)
   --
   -- Delete all files from specified folder in cloud storage
   -- pBucketName: 'INBOX', 'DATA', 'HISTORY'
   -- pFolderPrefix: folder path within bucket (e.g., 'C2D/UC_DISSEM/UC_NMA_DISSEM/')
   --
   IS
      vBucketUri              VARCHAR2(2000);
      vFolderUri              VARCHAR2(2000);
      vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
      vFilesDeleted           PLS_INTEGER := 0;
      vObjectName             VARCHAR2(4000);
      vFullObjectUri          VARCHAR2(4000);

      -- Cursor to list all objects in the folder
      CURSOR c_objects IS
         SELECT object_name
         FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(
            credential_name => ENV_MANAGER.gvCredentialName,
            location_uri    => vBucketUri
         ))
         WHERE object_name IS NOT NULL
         AND object_name LIKE pFolderPrefix || '%';

   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST(
         'pBucketName => '''||nvl(pBucketName, 'NULL')||'''',
         'pFolderPrefix => '''||nvl(pFolderPrefix, 'NULL')||''''
      ));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);

      -- Get bucket URI based on bucket name
      vBucketUri := GET_BUCKET_URI(pBucketName);

      ENV_MANAGER.LOG_PROCESS_EVENT('Listing objects in bucket with prefix: ' || pFolderPrefix, 'DEBUG', vBucketUri);

      -- List and delete all objects in the folder
      FOR obj_rec IN c_objects LOOP
         vObjectName := obj_rec.object_name;
         vFullObjectUri := vBucketUri || vObjectName;

         BEGIN
            ENV_MANAGER.LOG_PROCESS_EVENT('Deleting object', 'DEBUG', vFullObjectUri);

            DBMS_CLOUD.DELETE_OBJECT(
               credential_name => ENV_MANAGER.gvCredentialName,
               object_uri      => vFullObjectUri
            );

            vFilesDeleted := vFilesDeleted + 1;
            ENV_MANAGER.LOG_PROCESS_EVENT('Object deleted successfully', 'DEBUG', vObjectName);

         EXCEPTION
            WHEN OTHERS THEN
               ENV_MANAGER.LOG_PROCESS_EVENT('Error deleting object: ' || vObjectName || ' - ' || SQLERRM, 'ERROR', vParameters);
               -- Continue with next file instead of stopping the whole process
         END;
      END LOOP;

      ENV_MANAGER.LOG_PROCESS_EVENT('Total files deleted: ' || vFilesDeleted, 'INFO', vParameters);
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO', vParameters);

   EXCEPTION
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT('Error in DELETE_FOLDER_CONTENTS: ' || SQLERRM, 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE ENV_MANAGER.ERR_UNKNOWN;
   END DELETE_FOLDER_CONTENTS;

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

   PROCEDURE PROCESS_SOURCE_FILE(pSourceFileReceivedName IN VARCHAR2)
   --
   -- Ubmrella procedure that calls
   --   - REGISTER_SOURCE_FILE_RECEIVED
   --   - CREATE_EXTERNAL_TABLE
   --   - VALIDATE_SOURCE_FILE_RECEIVED
   --   - DROP_EXTERNAL_TABLE
   --   - MOVE_FILE
   IS
      vSourceFileId NUMBER;
      vParameters   CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedName => '||nvl(pSourceFileReceivedName, 'NULL')));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);
      ----
      vSourceFileId := REGISTER_SOURCE_FILE_RECEIVED(pSourceFileReceivedName);
      CREATE_EXTERNAL_TABLE(vSourceFileId);
      VALIDATE_SOURCE_FILE_RECEIVED(vSourceFileId);
      DROP_EXTERNAL_TABLE(vSourceFileId);
--      COPY_FILE(vSourceFileId, 'ODS');
      MOVE_FILE(vSourceFileId, 'ODS');
      SET_SOURCE_FILE_RECEIVED_STATUS(pSourceFileReceivedKey => vSourceFileId, pStatus => 'READY_FOR_INGESTION');


      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);

   EXCEPTION
      -- -20001
      WHEN ENV_MANAGER.ERR_EMPTY_FILEURI_AND_RECKEY THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_EMPTY_FILEURI_AND_RECKEY), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_EMPTY_FILEURI_AND_RECKEY, ENV_MANAGER.MSG_EMPTY_FILEURI_AND_RECKEY);
      -- -20002
      WHEN ENV_MANAGER.ERR_NO_CONFIG_MATCH_FOR_FILEURI THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_NO_CONFIG_MATCH_FOR_FILEURI), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_MATCH_FOR_FILEURI, ENV_MANAGER.MSG_NO_CONFIG_MATCH_FOR_FILEURI);
      -- -20003
      WHEN ENV_MANAGER.ERR_MULTIPLE_MATCH_FOR_SRCFILE THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MULTIPLE_MATCH_FOR_SRCFILE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTIPLE_MATCH_FOR_SRCFILE, ENV_MANAGER.MSG_MULTIPLE_MATCH_FOR_SRCFILE);
      -- -20004
      WHEN ENV_MANAGER.ERR_MISSING_COLUMN_DATE_FORMAT THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT, ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT);
      -- -20005
      WHEN ENV_MANAGER.ERR_MULTIPLE_COLUMN_DATE_FORMAT THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTIPLE_COLUMN_DATE_FORMAT, ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT);
      -- -20006
      WHEN ENV_MANAGER.ERR_DIDNT_GET_LOAD_OPERATION_ID THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_DIDNT_GET_LOAD_OPERATION_ID, ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT);
      -- -20007
      WHEN ENV_MANAGER.ERR_NO_CONFIG_FOR_RECEIVED_FILE THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_FOR_RECEIVED_FILE, ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT);
      -- -20008
      WHEN ENV_MANAGER.ERR_MULTI_CONFIG_FOR_RECEIVED_FILE THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTI_CONFIG_FOR_RECEIVED_FILE, ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT);
      -- -20009
      WHEN ENV_MANAGER.ERR_FILE_NOT_FOUND_ON_CLOUD THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_NOT_FOUND_ON_CLOUD, ENV_MANAGER.MSG_FILE_NOT_FOUND_ON_CLOUD);
      -- -20010
      WHEN ENV_MANAGER.ERR_FILE_VALIDATION_FAILED THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_FILE_VALIDATION_FAILED), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_VALIDATION_FAILED, ENV_MANAGER.MSG_FILE_VALIDATION_FAILED);
      -- -20011
      WHEN ENV_MANAGER.ERR_NO_CONFIG_MATCH THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_NO_CONFIG_MATCH), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NO_CONFIG_MATCH, ENV_MANAGER.MSG_NO_CONFIG_MATCH);
      -- -20012
      WHEN ENV_MANAGER.ERR_UNKNOWN_PREFIX THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_UNKNOWN_PREFIX), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN_PREFIX, ENV_MANAGER.MSG_UNKNOWN_PREFIX);
      -- -20013
      WHEN ENV_MANAGER.ERR_TABLE_NOT_EXISTS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_TABLE_NOT_EXISTS), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_TABLE_NOT_EXISTS, ENV_MANAGER.MSG_TABLE_NOT_EXISTS);
      -- -20014
      WHEN ENV_MANAGER.ERR_COLUMN_NOT_EXISTS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_COLUMN_NOT_EXISTS), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_COLUMN_NOT_EXISTS, ENV_MANAGER.MSG_COLUMN_NOT_EXISTS);
      -- -20015
      WHEN ENV_MANAGER.ERR_UNSUPPORTED_DATA_TYPE THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_UNSUPPORTED_DATA_TYPE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNSUPPORTED_DATA_TYPE, ENV_MANAGER.MSG_UNSUPPORTED_DATA_TYPE);
      -- -20016
      WHEN ENV_MANAGER.ERR_MISSING_SOURCE_KEY THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MISSING_SOURCE_KEY), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MISSING_SOURCE_KEY, ENV_MANAGER.MSG_MISSING_SOURCE_KEY);
      -- -20017
      WHEN ENV_MANAGER.ERR_NULL_SOURCE_FILE_CONFIG_KEY THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_NULL_SOURCE_FILE_CONFIG_KEY), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NULL_SOURCE_FILE_CONFIG_KEY, ENV_MANAGER.MSG_NULL_SOURCE_FILE_CONFIG_KEY);
      -- -20018
      WHEN ENV_MANAGER.ERR_DUPLICATED_SOURCE_KEY THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_DUPLICATED_SOURCE_KEY), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_DUPLICATED_SOURCE_KEY, ENV_MANAGER.MSG_DUPLICATED_SOURCE_KEY);
      -- -20019
      WHEN ENV_MANAGER.ERR_MISSING_CONTAINER_CONFIG THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MISSING_CONTAINER_CONFIG), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MISSING_CONTAINER_CONFIG, ENV_MANAGER.MSG_MISSING_CONTAINER_CONFIG);
      -- -20020
      WHEN ENV_MANAGER.ERR_MULTIPLE_CONTAINER_ENTRIES THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_MULTIPLE_CONTAINER_ENTRIES), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTIPLE_CONTAINER_ENTRIES, ENV_MANAGER.MSG_MULTIPLE_CONTAINER_ENTRIES);
      -- -20021
      WHEN ENV_MANAGER.ERR_WRONG_DESTINATION_PARAM THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_WRONG_DESTINATION_PARAM), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_WRONG_DESTINATION_PARAM, ENV_MANAGER.MSG_WRONG_DESTINATION_PARAM);
      -- -20022
      WHEN ENV_MANAGER.ERR_FILE_NOT_EXISTS_ON_CLOUD THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_FILE_NOT_EXISTS_ON_CLOUD), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_NOT_EXISTS_ON_CLOUD, ENV_MANAGER.MSG_FILE_NOT_EXISTS_ON_CLOUD);
      -- -20023
      WHEN ENV_MANAGER.ERR_FILE_ALREADY_REGISTERED THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_FILE_ALREADY_REGISTERED), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_FILE_ALREADY_REGISTERED, ENV_MANAGER.MSG_FILE_ALREADY_REGISTERED);
      -- -20024
      WHEN ENV_MANAGER.ERR_WRONG_DATE_TIMESTAMP_FORMAT THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_WRONG_DATE_TIMESTAMP_FORMAT), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_WRONG_DATE_TIMESTAMP_FORMAT, ENV_MANAGER.MSG_WRONG_DATE_TIMESTAMP_FORMAT);

      -- -20999
      WHEN ENV_MANAGER.ERR_UNKNOWN THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> ENV_MANAGER.CODE_UNKNOWN), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.MSG_UNKNOWN);


      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN, 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));

   END PROCESS_SOURCE_FILE;


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

   FUNCTION PROCESS_SOURCE_FILE(pSourceFileReceivedName IN VARCHAR2)   
   RETURN PLS_INTEGER
   IS
      vParameters   CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileReceivedName => '||nvl(pSourceFileReceivedName, 'NULL')));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);
      ----
      PROCESS_SOURCE_FILE(pSourceFileReceivedName => pSourceFileReceivedName);
      ----
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);
      RETURN SQLCODE;
   EXCEPTION
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RETURN SQLCODE;
   END PROCESS_SOURCE_FILE;

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

   FUNCTION GET_DATE_FORMAT(
      pTemplateTableName IN VARCHAR2,
      pColumnName  IN VARCHAR2
   )
   RETURN VARCHAR2
   IS
      vDateFormat A_COLUMN_DATE_FORMAT.DATE_FORMAT%TYPE;
      vParameters CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
      vColumnName VARCHAR2(200);
      vGetDefault BOOLEAN := FALSE;
   BEGIN
      vColumnName := trim(pColumnName);
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pTemplateTableName => '''||nvl(pTemplateTableName, 'NULL')||''''
                                                                  ,'pColumnName => '''||nvl(vColumnName, 'NULL')||''''));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      BEGIN
         SELECT DATE_FORMAT
           INTO vDateFormat
           FROM CT_MRDS.A_COLUMN_DATE_FORMAT F
          WHERE F.TEMPLATE_TABLE_NAME = pTemplateTableName
            AND F.COLUMN_NAME = vColumnName;

      EXCEPTION 
         WHEN NO_DATA_FOUND THEN
            vGetDefault := TRUE;
--               ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT, 'ERROR', vParameters);
--               RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT, ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT);
         WHEN TOO_MANY_ROWS THEN
            -- Below error should not happened because:
            -- Unique constraint added on table A_COLUMN_DATE_FORMAT on columns: (TEMPLATE_TABLE_NAME, COLUMN_NAME)
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTIPLE_COLUMN_DATE_FORMAT, ENV_MANAGER.MSG_MULTIPLE_COLUMN_DATE_FORMAT);
      END;
      IF vGetDefault THEN
         BEGIN 
            SELECT DATE_FORMAT
              INTO vDateFormat
              FROM CT_MRDS.A_COLUMN_DATE_FORMAT F
             WHERE F.TEMPLATE_TABLE_NAME = pTemplateTableName
               AND F.COLUMN_NAME = 'DEFAULT';
         EXCEPTION 
            WHEN NO_DATA_FOUND THEN
               vDateFormat := ENV_MANAGER.gvDefaultDateFormat;
         END;
      END IF;

      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);
      RETURN vDateFormat;
   END GET_DATE_FORMAT;

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

   PROCEDURE GENERATE_EXTERNAL_TABLE_PARAMS (

      pTemplateTableName IN VARCHAR2,
      pColumnList  OUT CLOB,
      pFieldList   OUT CLOB
   ) 
   IS
      vSchemaName VARCHAR2(200);
      vTableName  VARCHAR2(200);
      vParameters CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
      vMaxColumnNameLength PLS_INTEGER := 0;
      vColType varchar2(200);
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pTemplateTableName => '''||nvl(pTemplateTableName, 'NULL')||''''
                                                                  ,'pColumnList => '''||nvl(pColumnList, 'NULL')||''''
                                                                    ,'pFieldList = '''||nvl(pFieldList, 'NULL')||''''
                                                            ));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      vSchemaName := REPLACE(REGEXP_SUBSTR(pTemplateTableName,'.*\.'),'.','');
      ENV_MANAGER.LOG_PROCESS_EVENT('vSchemaName','DEBUG', vSchemaName);
      vTableName := REPLACE(REGEXP_SUBSTR(pTemplateTableName,'\..*'),'.','');
      ENV_MANAGER.LOG_PROCESS_EVENT('vTableName','DEBUG', vTableName);
      FOR rec IN (
           SELECT 
                  '"'||column_name||'"' as quoted_column_name,
                  column_name,
                  data_type,
                  data_length,
                  data_precision,
                  data_scale,
                  column_id,
                  max(length(column_name)+1) over (partition by table_name) as max_column_name_length
             FROM all_tab_columns
            WHERE table_name = UPPER(vTableName)
              AND owner = NVL(UPPER(vSchemaName), USER)
            ORDER BY column_id
       ) LOOP
           -- Build the column_list string
--           if length(rec.column_name) > vMaxColumnNameLength then vMaxColumnNameLength:= length(rec.column_name); end if;
           rec.quoted_column_name := rpad(rec.quoted_column_name, rec.max_column_name_length+2, ' ');

           vColType := 
               CASE
                   WHEN rec.data_type IN ('CHAR', 'NCHAR', 'VARCHAR2', 'NVARCHAR2') THEN
                       rec.quoted_column_name || ' ' || rec.data_type || '(' || rec.data_length || ')'
                   WHEN rec.data_type = 'NUMBER' THEN
                       rec.quoted_column_name || ' ' || rec.data_type ||
                       CASE
                           WHEN rec.data_precision IS NOT NULL AND rec.data_scale IS NOT NULL THEN
                               '(' || rec.data_precision || ',' || rec.data_scale || ')'
                           WHEN rec.data_precision IS NOT NULL THEN
                               '(' || rec.data_precision || ')'
                           ELSE
                               ''
                       END
                   WHEN rec.data_type IN ('RAW') THEN
                       rec.quoted_column_name || ' ' || rec.data_type || '(' || rec.data_length || ')'
                   WHEN REGEXP_SUBSTR(rec.data_type, '^[A-Z]+') IN ('DATE', 'TIMESTAMP') THEN
                       rec.quoted_column_name || ' ' || rec.data_type
                   ELSE
                       rec.quoted_column_name || ' ' || rec.data_type
               END;
           pColumnList := pColumnList ||vColType ||cgBL|| ',';
           -- Build the field_list string
           pFieldList := pFieldList || 
            CASE
             WHEN REGEXP_SUBSTR(rec.data_type, '^[A-Z]+') IN ('DATE', 'TIMESTAMP') THEN
                rec.quoted_column_name || ' DATE ' || CHR(39) || GET_DATE_FORMAT(pTemplateTableName => pTemplateTableName, pColumnName => rec.column_name) || CHR(39)
             WHEN rec.data_type IN ('CHAR', 'NCHAR', 'VARCHAR2', 'NVARCHAR2') THEN
                rec.quoted_column_name || ' CHAR(' || rec.data_length || ')'
             ELSE
                rec.quoted_column_name
            END ||cgBL|| ',';


      END LOOP;

      -- Remove the trailing comma and space from the strings
      pColumnList := ' '||RTRIM(pColumnList, ',');
      pFieldList := ' '||RTRIM(pFieldList, ',');
      ENV_MANAGER.LOG_PROCESS_EVENT('vColumnList',       'DEBUG', pColumnList);
      -- TO_DO !!!
      -- Add check if pColumnList/pFieldList is empty or not
      -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!



       -- Output the generated column_list and field_list
--       DBMS_OUTPUT.PUT_LINE('column_list => ' || pColumnList);
      ENV_MANAGER.LOG_PROCESS_EVENT('column_list' ,'DEBUG',pColumnList);
--       DBMS_OUTPUT.PUT_LINE('field_list => ' || pFieldList);
      ENV_MANAGER.LOG_PROCESS_EVENT('field_list' ,'DEBUG',pFieldList);
--       ENV_MANAGER.LOG_PROCESS_EVENT('field_list => '||cgBL||' '|| replace(pFieldList, ', ',cgBL||','),'DEBUG',vParameters);
      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);

   EXCEPTION
--      WHEN ENV_MANAGER.ERR_MISSING_COLUMN_DATE_FORMAT THEN
--         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MISSING_COLUMN_DATE_FORMAT, 'ERROR', vParameters);
--         RAISE_ERROR(ENV_MANAGER.CODE_MISSING_COLUMN_DATE_FORMAT);
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));
   END GENERATE_EXTERNAL_TABLE_PARAMS;

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

   PROCEDURE EXPORT_TABLE_DATA (
      pSchemaName      IN VARCHAR2,
      pTableName       IN VARCHAR2,
      pKeyColumnName   IN VARCHAR2,
      pBucketName      IN VARCHAR2,
      pFolderName      IN VARCHAR2,
      pNamespace       IN VARCHAR2 default ENV_MANAGER.gvNameSpace,
      pRegion          IN VARCHAR2 default ENV_MANAGER.gvRegion,
      pCredentialName  IN VARCHAR2 default ENV_MANAGER.gvCredentialName
   )
   IS
      -- Type definition for key values
      TYPE key_value_tab IS TABLE OF VARCHAR2(4000);
      vKeyValues       key_value_tab;
      vCount           INTEGER;
      vSql             VARCHAR2(4000);
      vKeyValue        VARCHAR2(4000);
      vQuery           VARCHAR2(32767);
      vUri             VARCHAR2(4000);
      vDataType        VARCHAR2(30);
      vTableName       VARCHAR2(128);
      vSchemaName      VARCHAR2(128);
      vKeyColumnName   VARCHAR2(128);
      vParameters      VARCHAR2(4000);


      -- Function to sanitize file names
      FUNCTION sanitizeFilename(pFilename IN VARCHAR2) RETURN VARCHAR2 IS
          vFilename VARCHAR2(1000);
      BEGIN
          -- Replace any disallowed characters with underscores
          vFilename := REGEXP_REPLACE(pFilename, '[^a-zA-Z0-9._-]', '_');
          RETURN vFilename;
      END sanitizeFilename;

   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST(    'pSchemaName => '''||nvl(pSchemaName, 'NULL')||''''
                                                                ,'pTableName => '''||nvl(pTableName, 'NULL')||''''
                                                            ,'pKeyColumnName => '''||nvl(pKeyColumnName, 'NULL')||''''
                                                               ,'pBucketName => '''||nvl(pBucketName, 'NULL')||''''
                                                               ,'pFolderName => '''||nvl(pFolderName, 'NULL')||''''
                                                                ,'pNamespace => '''||nvl(pNamespace, 'NULL')||''''
                                                                   ,'pRegion => '''||nvl(pRegion, 'NULL')||''''
                                                           ,'pCredentialName => '''||nvl(pCredentialName, 'NULL')||''''
                                                            ));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);
      -- Convert table and column names to uppercase to match data dictionary
      vTableName := UPPER(pTableName);
      vSchemaName := UPPER(pSchemaName);
      vKeyColumnName := UPPER(pKeyColumnName);

      -- Check if table exists
      SELECT COUNT(*) INTO vCount
      FROM all_tables
      WHERE table_name = vTableName
        AND owner = vSchemaName;

      IF vCount = 0 THEN
         ENV_MANAGER.MSG_TABLE_NOT_EXISTS := ENV_MANAGER.MSG_TABLE_NOT_EXISTS ||': '||vTableName;
         RAISE ENV_MANAGER.ERR_TABLE_NOT_EXISTS;
      END IF;

      -- Check if key column exists
      SELECT COUNT(*) INTO vCount
      FROM all_tab_columns
      WHERE table_name = vTableName
        AND column_name = vKeyColumnName
        AND owner = vSchemaName;

      IF vCount = 0 THEN
         ENV_MANAGER.MSG_COLUMN_NOT_EXISTS := ENV_MANAGER.MSG_COLUMN_NOT_EXISTS ||' (TableName.ColumnName): '||vTableName||'.'||vKeyColumnName;
         RAISE ENV_MANAGER.ERR_COLUMN_NOT_EXISTS;

      END IF;

      -- Get the data type of the key column
      SELECT data_type INTO vDataType
      FROM all_tab_columns
      WHERE table_name = vTableName
        AND column_name = vKeyColumnName
        AND owner = vSchemaName;

      vTableName := DBMS_ASSERT.SCHEMA_NAME(vSchemaName) || '.' || DBMS_ASSERT.simple_sql_name(vTableName);
      -- Fetch unique key values
      vSql := 'SELECT DISTINCT ' || DBMS_ASSERT.simple_sql_name(vKeyColumnName) ||
               ' FROM ' || vTableName;
      EXECUTE IMMEDIATE vSql BULK COLLECT INTO vKeyValues;

      -- Loop over each unique key value
      FOR i IN 1 .. vKeyValues.COUNT LOOP
          vKeyValue := vKeyValues(i);

         -- Construct the query to extract data for the current key value
         IF vDataType IN ('VARCHAR2', 'CHAR', 'NCHAR', 'NVARCHAR2') THEN
           vQuery := 'SELECT * FROM ' || vTableName ||
                      ' WHERE ' || DBMS_ASSERT.simple_sql_name(vKeyColumnName) || ' = ' || CHR(39) || vKeyValue || CHR(39);
         ELSIF vDataType IN ('NUMBER', 'FLOAT', 'BINARY_FLOAT', 'BINARY_DOUBLE') THEN
           vQuery := 'SELECT * FROM ' || vTableName ||
                      ' WHERE ' || DBMS_ASSERT.simple_sql_name(vKeyColumnName) || ' = ' || vKeyValue;
         ELSIF vDataType LIKE 'TIMESTAMP%' OR vDataType = 'DATE' THEN
           vQuery := 'SELECT * FROM ' || vTableName ||
                      ' WHERE ' || DBMS_ASSERT.simple_sql_name(vKeyColumnName) ||
                      ' = TO_TIMESTAMP(' || CHR(39) || vKeyValue || CHR(39) ||', ''YYYY-MM-DD HH24:MI:SS.FF'')';
         ELSE
            ENV_MANAGER.MSG_UNSUPPORTED_DATA_TYPE := ENV_MANAGER.MSG_UNSUPPORTED_DATA_TYPE ||' vDataType: '||vDataType;
            RAISE ENV_MANAGER.ERR_UNSUPPORTED_DATA_TYPE;
         END IF;

         -- Construct the URI for the file in OCI Object Storage
         vUri := 'https://objectstorage.' || pRegion || '.oraclecloud.com/n/' || pNamespace ||
                '/b/' || pBucketName || '/o/' ||
                CASE WHEN pFolderName IS NOT NULL THEN pFolderName || '/' ELSE '' END ||
                sanitizeFilename(vKeyValue) || '.csv';

          -- Use DBMS_CLOUD package to export data to the URI
          DBMS_CLOUD.EXPORT_DATA(
              credential_name => pCredentialName,
              file_uri_list   => vUri,
              query           => vQuery,
              format          => json_object('type' VALUE 'CSV')
              -- Bind the key value if needed
              --job_params      => CASE
                                     --WHEN vDataType IN ('VARCHAR2', 'CHAR', 'NCHAR', 'NVARCHAR2', 'DATE', 'TIMESTAMP', 'TIMESTAMP WITH TIME ZONE', 'TIMESTAMP WITH LOCAL TIME ZONE') THEN
                                         --dbms_cloud.tabular_parameters(sys.dbms_cloud.name_value('BIND_VALUE', vKeyValue))
                                     --ELSE
                                         --NULL
                                 --END
          );
      END LOOP;
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);
   EXCEPTION 
      WHEN ENV_MANAGER.ERR_TABLE_NOT_EXISTS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_TABLE_NOT_EXISTS, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_TABLE_NOT_EXISTS, ENV_MANAGER.MSG_TABLE_NOT_EXISTS);
      WHEN ENV_MANAGER.ERR_COLUMN_NOT_EXISTS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_COLUMN_NOT_EXISTS, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_COLUMN_NOT_EXISTS, ENV_MANAGER.MSG_COLUMN_NOT_EXISTS);
      WHEN ENV_MANAGER.ERR_UNSUPPORTED_DATA_TYPE THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNSUPPORTED_DATA_TYPE, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNSUPPORTED_DATA_TYPE, ENV_MANAGER.MSG_UNSUPPORTED_DATA_TYPE);

   END EXPORT_TABLE_DATA;

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

   PROCEDURE EXPORT_TABLE_DATA_BY_DATE (
      pSchemaName      IN VARCHAR2,
      pTableName       IN VARCHAR2,
      pKeyColumnName   IN VARCHAR2,
      pBucketName      IN VARCHAR2,
      pFolderName      IN VARCHAR2,
      pMinDate         IN DATE     default DATE '1900-01-01',
      pMaxDate         IN DATE     default SYSDATE,
      pNamespace       IN VARCHAR2 default ENV_MANAGER.gvNameSpace,
      pRegion          IN VARCHAR2 default ENV_MANAGER.gvRegion,
      pCredentialName  IN VARCHAR2 default ENV_MANAGER.gvCredentialName
   )
   IS
      -- Type definition for key values
      TYPE key_value_tab IS TABLE OF VARCHAR2(4000);

      vKeyValuesYear   key_value_tab;
      vKeyValuesMonth  key_value_tab;

      vCount           INTEGER;
      vSql             VARCHAR2(4000);
      vKeyValueYear    VARCHAR2(4000);
      vKeyValueMonth   VARCHAR2(4000);
      vQuery           VARCHAR2(32767);
      vUri             VARCHAR2(4000);
      vDataType        VARCHAR2(30);
      vTableName       VARCHAR2(128);
      vSchemaName      VARCHAR2(128);
      vKeyColumnName   VARCHAR2(128);
      vParameters      CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;

      -- Function to sanitize file names
      FUNCTION sanitizeFilename(pFilename IN VARCHAR2) RETURN VARCHAR2 IS
          vFilename VARCHAR2(1000);
      BEGIN
          -- Replace any disallowed characters with underscores
          vFilename := REGEXP_REPLACE(pFilename, '[^a-zA-Z0-9._-]', '_');
          RETURN vFilename;
      END sanitizeFilename;

   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST(    'pSchemaName => '''||nvl(pSchemaName, 'NULL')||''''
                                                                ,'pTableName => '''||nvl(pTableName, 'NULL')||''''
                                                            ,'pKeyColumnName => '''||nvl(pKeyColumnName, 'NULL')||''''
                                                               ,'pBucketName => '''||nvl(pBucketName, 'NULL')||''''
                                                               ,'pFolderName => '''||nvl(pFolderName, 'NULL')||''''
                                                                  ,'pMinDate => '''||nvl(TO_CHAR(pMinDate, 'YYYY-MM-DD HH24:MI:SS'), 'NULL')||''''
                                                                  ,'pMaxDate => '''||nvl(TO_CHAR(pMaxDate, 'YYYY-MM-DD HH24:MI:SS'), 'NULL')||''''
                                                                ,'pNamespace => '''||nvl(pNamespace, 'NULL')||''''
                                                                   ,'pRegion => '''||nvl(pRegion, 'NULL')||''''
                                                           ,'pCredentialName => '''||nvl(pCredentialName, 'NULL')||''''
                                                            ));

      -- Convert table and column names to uppercase to match data dictionary
      vTableName := UPPER(pTableName);
      vSchemaName := UPPER(pSchemaName);
      vKeyColumnName := UPPER(pKeyColumnName);

      -- Check if table exists
      SELECT COUNT(*) INTO vCount
      FROM all_tables
      WHERE table_name = vTableName
        AND owner = vSchemaName;

      IF vCount = 0 THEN
         ENV_MANAGER.MSG_TABLE_NOT_EXISTS := ENV_MANAGER.MSG_TABLE_NOT_EXISTS ||': '||vTableName;
			RAISE ENV_MANAGER.ERR_TABLE_NOT_EXISTS;
      END IF;

      -- Check if key column exists
      SELECT COUNT(*) INTO vCount
      FROM all_tab_columns
      WHERE table_name = vTableName
        AND column_name = vKeyColumnName
        AND owner = vSchemaName;

      IF vCount = 0 THEN
         ENV_MANAGER.MSG_COLUMN_NOT_EXISTS := ENV_MANAGER.MSG_COLUMN_NOT_EXISTS ||' (TableName.ColumnName): '||vTableName||'.'||vKeyColumnName;
			RAISE ENV_MANAGER.ERR_COLUMN_NOT_EXISTS;
      END IF;

      -- Get the data type of the key column
      SELECT data_type INTO vDataType
      FROM all_tab_columns
      WHERE table_name = vTableName
        AND column_name = vKeyColumnName
        AND owner = vSchemaName;

      vTableName := DBMS_ASSERT.SCHEMA_NAME(vSchemaName) || '.' || DBMS_ASSERT.simple_sql_name(vTableName);
      -- Fetch unique key values
      vSql := 'SELECT DISTINCT TO_CHAR(L.LOAD_START,''YYYY'') AS YR, TO_CHAR(L.LOAD_START,''MM'') AS MN
                 FROM ' || vTableName || ' T, CT_ODS.A_LOAD_HISTORY L
                WHERE T.' || DBMS_ASSERT.simple_sql_name(vKeyColumnName) || ' = L.A_WORKFLOW_HISTORY_KEY
                  AND L.LOAD_START >= :pMinDate
                  AND L.LOAD_START <= :pMaxDate            
              ' ;
      EXECUTE IMMEDIATE vSql BULK COLLECT INTO vKeyValuesYear, vKeyValuesMonth USING pMinDate, pMaxDate;

      -- Loop over each unique key value
      FOR i IN 1 .. vKeyValuesYear.COUNT  LOOP
          vKeyValueYear := vKeyValuesYear(i);
          vKeyValueMonth := vKeyValuesMonth(i);
          -- Construct the query to extract data for the current key value

          vQuery := 'SELECT T.* 
                       FROM ' || vTableName || ' T, CT_ODS.A_LOAD_HISTORY L
                      WHERE T.' || DBMS_ASSERT.simple_sql_name(vKeyColumnName) || ' = L.A_WORKFLOW_HISTORY_KEY
                        AND TO_CHAR(L.LOAD_START,''YYYY'') = ' || CHR(39) || vKeyValueYear || CHR(39) || '
                        AND TO_CHAR(L.LOAD_START,''MM'') = ' || CHR(39) || vKeyValueMonth || CHR(39) || '
                        AND L.LOAD_START >= TO_DATE(' || CHR(39) || TO_CHAR(pMinDate, 'YYYY-MM-DD HH24:MI:SS') || CHR(39) || ', ''YYYY-MM-DD HH24:MI:SS'')
                        AND L.LOAD_START <= TO_DATE(' || CHR(39) || TO_CHAR(pMaxDate, 'YYYY-MM-DD HH24:MI:SS') || CHR(39) || ', ''YYYY-MM-DD HH24:MI:SS'')';

          -- Construct the URI for the file in OCI Object Storage
          vUri := 'https://objectstorage.' || pRegion || '.oraclecloud.com/n/' || pNamespace ||
                   '/b/' || pBucketName || '/o/' ||
                   CASE WHEN pFolderName IS NOT NULL THEN pFolderName || '/' ELSE '' END ||
                   'YEAR=' || sanitizeFilename(vKeyValueYear) || '/' ||
                   'MONTH=' || sanitizeFilename(vKeyValueMonth) || '/' ||
                   sanitizeFilename(vKeyValueYear) || sanitizeFilename(vKeyValueMonth) || '.parquet';

          --DBMS_OUTPUT.PUT_LINE(vQuery);

          -- Use DBMS_CLOUD package to export data to the URI
          DBMS_CLOUD.EXPORT_DATA(
              credential_name => pCredentialName,
              file_uri_list   => vUri,
              query           => vQuery,
              format          => json_object('type' VALUE 'parquet')
          );
      END LOOP;

      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);
   EXCEPTION 
      WHEN ENV_MANAGER.ERR_TABLE_NOT_EXISTS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_TABLE_NOT_EXISTS, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_TABLE_NOT_EXISTS, ENV_MANAGER.MSG_TABLE_NOT_EXISTS);
      WHEN ENV_MANAGER.ERR_COLUMN_NOT_EXISTS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_COLUMN_NOT_EXISTS, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_COLUMN_NOT_EXISTS, ENV_MANAGER.MSG_COLUMN_NOT_EXISTS);

   END EXPORT_TABLE_DATA_BY_DATE;

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

   PROCEDURE ADD_SOURCE (
      pSourceKey   IN CT_MRDS.A_SOURCE.A_SOURCE_KEY%TYPE,
      pSourceName  IN CT_MRDS.A_SOURCE.SOURCE_NAME%TYPE
   ) IS
      vParameters      CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      INSERT INTO CT_MRDS.A_SOURCE(A_SOURCE_KEY, SOURCE_NAME) VALUES (pSourceKey, pSourceName);
      COMMIT;
   EXCEPTION
      WHEN DUP_VAL_ON_INDEX THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_DUPLICATED_SOURCE_KEY, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_DUPLICATED_SOURCE_KEY, ENV_MANAGER.MSG_DUPLICATED_SOURCE_KEY);
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));
   END ADD_SOURCE;

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

   PROCEDURE DELETE_SOURCE_CASCADE (
      pSourceKey   IN CT_MRDS.A_SOURCE.A_SOURCE_KEY%TYPE
   ) IS
      vParameters          CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
      vSharedTemplateCount PLS_INTEGER := 0;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceKey => '''||nvl(pSourceKey, 'NULL')||''''));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);

      for rec in (select A_SOURCE_FILE_CONFIG_KEY, TEMPLATE_TABLE_NAME from CT_MRDS.A_SOURCE_FILE_CONFIG where A_SOURCE_KEY = pSourceKey) loop
         -- Delete processed file records
         delete from CT_MRDS.A_SOURCE_FILE_RECEIVED WHERE A_SOURCE_FILE_CONFIG_KEY = rec.A_SOURCE_FILE_CONFIG_KEY;
         ENV_MANAGER.LOG_PROCESS_EVENT('Deleted A_SOURCE_FILE_RECEIVED records for config key: '||rec.A_SOURCE_FILE_CONFIG_KEY,'DEBUG', vParameters);

         -- Check if TEMPLATE_TABLE_NAME is shared with other source systems before deleting date formats
         IF rec.TEMPLATE_TABLE_NAME IS NOT NULL THEN
            SELECT COUNT(DISTINCT A_SOURCE_KEY) 
            INTO vSharedTemplateCount
            FROM CT_MRDS.A_SOURCE_FILE_CONFIG 
            WHERE TEMPLATE_TABLE_NAME = rec.TEMPLATE_TABLE_NAME;

            -- Only delete date formats if template table is not shared with other sources
            IF vSharedTemplateCount <= 1 THEN
               delete from CT_MRDS.A_COLUMN_DATE_FORMAT WHERE TEMPLATE_TABLE_NAME = rec.TEMPLATE_TABLE_NAME;
               ENV_MANAGER.LOG_PROCESS_EVENT('Deleted A_COLUMN_DATE_FORMAT records for template: '||rec.TEMPLATE_TABLE_NAME,'DEBUG', vParameters);
            ELSE
               ENV_MANAGER.LOG_PROCESS_EVENT('Skipping A_COLUMN_DATE_FORMAT deletion - template table '||rec.TEMPLATE_TABLE_NAME||' is shared with '||vSharedTemplateCount||' source systems','WARNING', vParameters);
            END IF;
         END IF;

         -- Delete file configuration
         delete from CT_MRDS.A_SOURCE_FILE_CONFIG WHERE A_SOURCE_FILE_CONFIG_KEY = rec.A_SOURCE_FILE_CONFIG_KEY;
         ENV_MANAGER.LOG_PROCESS_EVENT('Deleted A_SOURCE_FILE_CONFIG record for config key: '||rec.A_SOURCE_FILE_CONFIG_KEY,'DEBUG', vParameters);
      end loop;

      -- Delete source system record
      DELETE FROM CT_MRDS.A_SOURCE where A_SOURCE_KEY = pSourceKey;
      ENV_MANAGER.LOG_PROCESS_EVENT('Deleted A_SOURCE record for source key: '||pSourceKey,'DEBUG', vParameters);

      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO', vParameters);

   EXCEPTION
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN, 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));
   END DELETE_SOURCE_CASCADE;

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

   FUNCTION GET_CONTAINER_SOURCE_FILE_CONFIG_KEY (
      pSourceFileId          IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID%TYPE
   ) RETURN PLS_INTEGER
   IS
     vSourceFileConfigKey PLS_INTEGER;
     vParameters          CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileId => '||nvl(to_char(pSourceFileId), 'NULL')));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      SELECT A_SOURCE_FILE_CONFIG_KEY
       INTO vSourceFileConfigKey 
       FROM CT_MRDS.A_SOURCE_FILE_CONFIG 
      WHERE SOURCE_FILE_ID   = pSourceFileId
        AND SOURCE_FILE_TYPE = 'CONTAINER';
   ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);
   RETURN vSourceFileConfigKey;

   EXCEPTION 
      WHEN NO_DATA_FOUND THEN
         ENV_MANAGER.MSG_MISSING_CONTAINER_CONFIG := 'No match in A_SOURCE_FILE_CONFIG where SOURCE_FILE_TYPE=''CONTAINER'' and SOURCE_FILE_ID = '''||pSourceFileId||'''';
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MISSING_CONTAINER_CONFIG, 'WARNING', vParameters);
         RETURN NULL;
      WHEN TOO_MANY_ROWS THEN
         ENV_MANAGER.MSG_MULTIPLE_CONTAINER_ENTRIES := 'GET_CONTAINER_SOURCE_FILE_CONFIG_KEY: Multiple SOURCE_FILE_TYPE=''CONTAINER'' matches for SOURCE_FILE_ID: '||pSourceFileId||' in A_SOURCE_FILE_CONFIG';
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MULTIPLE_CONTAINER_ENTRIES, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTIPLE_CONTAINER_ENTRIES, ENV_MANAGER.MSG_MULTIPLE_CONTAINER_ENTRIES);
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE ENV_MANAGER.ERR_UNKNOWN;

   END GET_CONTAINER_SOURCE_FILE_CONFIG_KEY;

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

   FUNCTION GET_SOURCE_FILE_CONFIG_KEY (
       pSourceFileType        IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_TYPE%TYPE DEFAULT 'INPUT'
      ,pSourceFileId          IN   CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID%TYPE
      ,pTableId               IN   CT_MRDS.A_SOURCE_FILE_CONFIG.TABLE_ID%TYPE
   ) RETURN PLS_INTEGER
   IS
     vSourceFileConfigKey PLS_INTEGER;
     vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST('pSourceFileType => '''||nvl(pSourceFileType, 'NULL')||''''
                                                             ,'pSourceFileId => '''||nvl(pSourceFileId, 'NULL')||''''
                                                                  ,'pTableId => '''||nvl(pTableId, 'NULL')||''''));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
      SELECT A_SOURCE_FILE_CONFIG_KEY
       INTO vSourceFileConfigKey 
       FROM CT_MRDS.A_SOURCE_FILE_CONFIG 
      WHERE SOURCE_FILE_TYPE = pSourceFileType
        AND SOURCE_FILE_ID   = pSourceFileId
        AND TABLE_ID         = pTableId;

      ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG', vParameters);
      RETURN vSourceFileConfigKey;

   EXCEPTION 
      WHEN NO_DATA_FOUND THEN
         RETURN NULL;
      WHEN TOO_MANY_ROWS THEN
         ENV_MANAGER.MSG_MULTIPLE_MATCH_FOR_SRCFILE := ENV_MANAGER.MSG_MULTIPLE_MATCH_FOR_SRCFILE
                      ||cgBL||'           '||'GET_SOURCE_FILE_CONFIG_KEY: Multiple matches in A_SOURCE_FILE_CONFIG table WHERE'
                      ||cgBL||'           '||'SOURCE_FILE_TYPE: '||pSourceFileType
                      ||cgBL||'           '||'SOURCE_FILE_ID:   '||pSourceFileId
                      ||cgBL||'           '||'TABLE_ID:         '||pTableId;
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MULTIPLE_MATCH_FOR_SRCFILE, 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MULTIPLE_MATCH_FOR_SRCFILE, ENV_MANAGER.MSG_MULTIPLE_MATCH_FOR_SRCFILE);
      WHEN OTHERS THEN
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE ENV_MANAGER.ERR_UNKNOWN;

   END GET_SOURCE_FILE_CONFIG_KEY;

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

   PROCEDURE ADD_SOURCE_FILE_CONFIG (
       pSourceKey             IN    CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_KEY%TYPE
      ,pSourceFileType        IN    CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_TYPE%TYPE
      ,pSourceFileId          IN    CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_ID%TYPE
      ,pSourceFileDesc        IN    CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_DESC%TYPE
      ,pSourceFileNamePattern IN    CT_MRDS.A_SOURCE_FILE_CONFIG.SOURCE_FILE_NAME_PATTERN%TYPE
      ,pTableId               IN    CT_MRDS.A_SOURCE_FILE_CONFIG.TABLE_ID%TYPE                  DEFAULT NULL
      ,pTemplateTableName     IN    CT_MRDS.A_SOURCE_FILE_CONFIG.TEMPLATE_TABLE_NAME%TYPE       DEFAULT NULL
      ,pContainerFileKey      IN    CT_MRDS.A_SOURCE_FILE_CONFIG.CONTAINER_FILE_KEY%TYPE        DEFAULT NULL
   ) IS
      vSourceFileConfigKey          PLS_INTEGER;
      vSourceKeyExists              PLS_INTEGER := 0;
      vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;

   BEGIN    
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST(             'pSourceKey => '''||nvl(to_char(pSourceKey), 'NULL')||''''
                                                                   ,'pSourceFileType => '''||nvl(to_char(pSourceFileType), 'NULL')||''''
                                                                     ,'pSourceFileId => '''||nvl(to_char(pSourceFileId), 'NULL')||''''
                                                                   ,'pSourceFileDesc => '''||nvl(to_char(pSourceFileDesc), 'NULL')||''''
                                                            ,'pSourceFileNamePattern => '''||nvl(to_char(pSourceFileNamePattern), 'NULL')||''''
                                                                          ,'pTableId => '''||nvl(to_char(pTableId), 'NULL')||''''
                                                                ,'pTemplateTableName => '''||nvl(to_char(pTemplateTableName), 'NULL')||''''
                                                                 ,'pContainerFileKey => '''||nvl(to_char(pContainerFileKey), 'NULL')||''''
                                                                   ,'pSourceFileType => '''||nvl(to_char(pSourceFileType), 'NULL')||''''
                                                            ));
      ENV_MANAGER.LOG_PROCESS_EVENT('Start','INFO', vParameters);
      INSERT INTO CT_MRDS.A_SOURCE_FILE_CONFIG(A_SOURCE_KEY, SOURCE_FILE_TYPE, SOURCE_FILE_ID, SOURCE_FILE_DESC, SOURCE_FILE_NAME_PATTERN, TABLE_ID, TEMPLATE_TABLE_NAME, CONTAINER_FILE_KEY)
      VALUES (pSourceKey, pSourceFileType, pSourceFileId, pSourceFileDesc, pSourceFileNamePattern, pTableId, pTemplateTableName, pContainerFileKey);
      COMMIT;
      ENV_MANAGER.LOG_PROCESS_EVENT('End','INFO',vParameters);
   EXCEPTION

      WHEN OTHERS THEN
         IF SQLCODE = -2291 THEN
            ENV_MANAGER.MSG_MISSING_SOURCE_KEY :=   'The Source with A_SOURCE_KEY: '''||pSourceKey||''' not found in parent table A_SOURCE.'
                                 ||cgBL||'First add a record to A_SOURCE:'
                                 ||cgBL||'call file_manager.add_source(pSourceKey => '''||pSourceKey||''', pSourceName => ''...'')'; 
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_MISSING_SOURCE_KEY, 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_MISSING_SOURCE_KEY, ENV_MANAGER.MSG_MISSING_SOURCE_KEY);
         ELSE
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN , 'ERROR', vParameters);
            ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
            RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));
         END IF;                           

   END ADD_SOURCE_FILE_CONFIG;

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

   PROCEDURE ADD_COLUMN_DATE_FORMAT (
       pTemplateTableName     IN   CT_MRDS.A_COLUMN_DATE_FORMAT.TEMPLATE_TABLE_NAME%TYPE
      ,pColumnName            IN   CT_MRDS.A_COLUMN_DATE_FORMAT.COLUMN_NAME%TYPE
      ,pDateFormat            IN   CT_MRDS.A_COLUMN_DATE_FORMAT.DATE_FORMAT%TYPE
   ) IS
      vParameters             CT_MRDS.A_PROCESS_LOG.PROCEDURE_PARAMETERS%TYPE;
   BEGIN    
      vParameters := ENV_MANAGER.FORMAT_PARAMETERS(SYS.ODCIVARCHAR2LIST( 'pTemplateTableName => '''||nvl(pTemplateTableName, 'NULL')||''''
                                                                   ,'pColumnName => '''||nvl(pColumnName, 'NULL')||''''
                                                                   ,'pDateFormat => '''||nvl(pDateFormat, 'NULL')||''''
                                                            ));

      ENV_MANAGER.LOG_PROCESS_EVENT('Start','DEBUG', vParameters);
--      vgSourceFileConfigKey := GET_SOURCE_FILE_CONFIG_KEY(pSourceFileId => pSourceFileId, pTableId => pTableId);
--      IF vgSourceFileConfigKey IS NULL THEN
--         RAISE ENV_MANAGER.ERR_NULL_SOURCE_FILE_CONFIG_KEY;
--      ELSE
         INSERT INTO CT_MRDS.A_COLUMN_DATE_FORMAT(TEMPLATE_TABLE_NAME, COLUMN_NAME, DATE_FORMAT)
         VALUES (pTemplateTableName, pColumnName, pDateFormat);
         COMMIT;
--      END IF;
   ENV_MANAGER.LOG_PROCESS_EVENT('End','DEBUG',vParameters);
   EXCEPTION
--      WHEN ENV_MANAGER.ERR_NULL_SOURCE_FILE_CONFIG_KEY THEN
--         ENV_MANAGER.MSG_NULL_SOURCE_FILE_CONFIG_KEY :=   'ADD_COLUMN_DATE_FORMAT: Could not find A_SOURCE_FILE_CONFIG_KEY where : '
--                                 ||cgBL||'SOURCE_FILE_ID = '||pSourceFileId
--                                 ||cgBL||'TABLE_ID = '||pTableId;
--         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_NULL_SOURCE_FILE_CONFIG_KEY, 'ERROR', vParameters);
--         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_NULL_SOURCE_FILE_CONFIG_KEY, ENV_MANAGER.MSG_NULL_SOURCE_FILE_CONFIG_KEY);
      WHEN OTHERS THEN
			ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.MSG_UNKNOWN, 'ERROR', vParameters);
         ENV_MANAGER.LOG_PROCESS_EVENT(ENV_MANAGER.GET_ERROR_STACK(pFormat => 'TABLE', pCode=> SQLCODE), 'ERROR', vParameters);
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));
   END ADD_COLUMN_DATE_FORMAT;

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

   FUNCTION GET_BUCKET_URI(pBucketName VARCHAR2)
   RETURN VARCHAR2
   IS
   BEGIN
      CASE pBucketName
         WHEN 'INBOX'   THEN RETURN ENV_MANAGER.gvInboxBucketUri;
         WHEN 'ODS'     THEN RETURN ENV_MANAGER.gvDataBucketUri;
         WHEN 'DATA'    THEN RETURN ENV_MANAGER.gvDataBucketUri;
         WHEN 'HISTORY' THEN RETURN ENV_MANAGER.gvHistoryBucketUri;
      ELSE
         RETURN NULL;
      END CASE;
   END;

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

   FUNCTION GET_DET_SOURCE_FILE_CONFIG_INFO (
       pSourceFileConfigKey      IN   CT_MRDS.A_SOURCE_FILE_CONFIG.A_SOURCE_FILE_CONFIG_KEY%TYPE
       ,pIncludeContainerInfo    IN PLS_INTEGER DEFAULT 1
       ,pIncludeColumnFormatInfo IN PLS_INTEGER DEFAULT 1
   ) RETURN VARCHAR2 
   ----
   -- Function to get info about File Configuration entry
   IS
      vSourceFileConfig    CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE;
      vContainerFileConfig CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE;
      vCount               PLS_INTEGER := 0;
      addColHeader         BOOLEAN     := TRUE;
      vMsgTmp              VARCHAR2(32000):= '';
      CURSOR cColumnFormat(vTableName A_COLUMN_DATE_FORMAT.TEMPLATE_TABLE_NAME%TYPE) IS 
                     SELECT * 
                      FROM CT_MRDS.A_COLUMN_DATE_FORMAT 
                     WHERE TEMPLATE_TABLE_NAME = vTableName;
      vColumnDateFormat A_COLUMN_DATE_FORMAT%ROWTYPE;

      FUNCTION FORMAT_CONFIG( pSourceFileConfig CT_MRDS.A_SOURCE_FILE_CONFIG%ROWTYPE, 
                              pTypeInfo         VARCHAR2 DEFAULT 'File Configuration', 
                              pLevel            VARCHAR2 DEFAULT '')
      RETURN VARCHAR2
      IS 
         vMsg VARCHAR2(9999);
      BEGIN
         vMsg := ''
                     ||cgBL||pLevel||''||'Details about '||pTypeInfo||':'
                     ||cgBL||pLevel||''||'--------------------------------'
                     ||cgBL||pLevel||'A_SOURCE_FILE_CONFIG_KEY             = '||pSourceFileConfig.A_SOURCE_FILE_CONFIG_KEY
                     ||cgBL||pLevel||'A_SOURCE_KEY                         = '||pSourceFileConfig.A_SOURCE_KEY
                     ||cgBL||pLevel||'SOURCE_FILE_TYPE                     = '||pSourceFileConfig.SOURCE_FILE_TYPE
                     ||cgBL||pLevel||'SOURCE_FILE_ID                       = '||pSourceFileConfig.SOURCE_FILE_ID
                     ||cgBL||pLevel||'SOURCE_FILE_DESC                     = '||pSourceFileConfig.SOURCE_FILE_DESC
                     ||cgBL||pLevel||'SOURCE_FILE_NAME_PATTERN             = '||pSourceFileConfig.SOURCE_FILE_NAME_PATTERN
                     ||cgBL||pLevel||'TABLE_ID                             = '||pSourceFileConfig.TABLE_ID
                     ||cgBL||pLevel||'TEMPLATE_TABLE_NAME                  = '||pSourceFileConfig.TEMPLATE_TABLE_NAME
                     ||cgBL||pLevel||'CONTAINER_FILE_KEY                   = '||pSourceFileConfig.CONTAINER_FILE_KEY
                     ||cgBL||pLevel||'ODS_SCHEMA_NAME                      = '||pSourceFileConfig.ODS_SCHEMA_NAME
                     ||cgBL||pLevel||'DAYS_FOR_HISTORY_THRESHOLD           = '||pSourceFileConfig.DAYS_FOR_HISTORY_THRESHOLD
                     ||cgBL||pLevel||'FILES_COUNT_OVER_HISTORY_THRESHOLD   = '||pSourceFileConfig.FILES_COUNT_OVER_HISTORY_THRESHOLD
                     ||cgBL||pLevel||'BYTES_SUM_OVER_HISTORY_THRESHOLD     = '||pSourceFileConfig.BYTES_SUM_OVER_HISTORY_THRESHOLD
                     ||cgBL||pLevel||'ROWS_COUNT_OVER_HISTORY_THRESHOLD    = '||pSourceFileConfig.ROWS_COUNT_OVER_HISTORY_THRESHOLD
                     ||cgBL||pLevel||'HOURS_TO_EXPIRE_STATISTICS           = '||pSourceFileConfig.HOURS_TO_EXPIRE_STATISTICS

                     ||cgBL||pLevel||''||'--------------------------------'
                     ;
         RETURN vMsg;
      END FORMAT_CONFIG;

   BEGIN
      vMsgTmp := '';
      -- Get Main Config
      BEGIN
         SELECT *
          INTO vSourceFileConfig 
          FROM CT_MRDS.A_SOURCE_FILE_CONFIG 
         WHERE A_SOURCE_FILE_CONFIG_KEY = pSourceFileConfigKey;

         vMsgTmp := FORMAT_CONFIG(pSourceFileConfig => vSourceFileConfig, pTypeInfo => 'File Configuration');
      EXCEPTION
         WHEN NO_DATA_FOUND THEN
         vMsgTmp := 'There is no config entry in A_SOURCE_FILE_CONFIG where  A_SOURCE_FILE_CONFIG_KEY = '||pSourceFileConfigKey;
         RETURN vMsgTmp;
      END;

      -- Get Container Config
      IF pIncludeContainerInfo > 0 THEN
         BEGIN
            SELECT *
             INTO vContainerFileConfig 
             FROM CT_MRDS.A_SOURCE_FILE_CONFIG 
            WHERE A_SOURCE_FILE_CONFIG_KEY = vSourceFileConfig.CONTAINER_FILE_KEY;

            vMsgTmp := vMsgTmp || cgBL || FORMAT_CONFIG(pSourceFileConfig => vContainerFileConfig, pTypeInfo => 'related Container Config', pLevel => '   ');

         EXCEPTION
            WHEN NO_DATA_FOUND THEN
            vMsgTmp := vMsgTmp|| cgBL || 'There is no CONTAINER config entry in A_SOURCE_FILE_CONFIG.';
   --         RETURN vMsgTmp;
         END;
      END IF;

      -- Get Column Date Format Config
      IF pIncludeColumnFormatInfo > 0 THEN
         BEGIN
            OPEN cColumnFormat(vTableName => vSourceFileConfig.TEMPLATE_TABLE_NAME);
            LOOP
               FETCH cColumnFormat INTO vColumnDateFormat;
               IF cColumnFormat%FOUND AND addColHeader THEN
                  vCount := 1; 
                  vMsgTmp := vMsgTmp||cgBL|| cgBL || '      Column Date Format config entries:';
                  vMsgTmp := vMsgTmp||cgBL||''||'      --------------------------------';
                  addColHeader := FALSE;
               END IF;
               EXIT WHEN cColumnFormat%NOTFOUND;
               vMsgTmp := vMsgTmp
                        ||cgBL||'      TEMPLATE_TABLE_NAME  = '||vColumnDateFormat.TEMPLATE_TABLE_NAME
                        ||cgBL||'      COLUMN_NAME          = '||vColumnDateFormat.COLUMN_NAME
                        ||cgBL||'      DATE_FORMAT          = '||vColumnDateFormat.DATE_FORMAT
                        ||cgBL||''||'      --------------------------------';
            END LOOP;
            If vCount=0 THEN
               vMsgTmp := vMsgTmp || cgBL || 'There is no Column Date Format config entries in A_COLUMN_DATE_FORMAT where TEMPLATE_TABLE_NAME = '||NVL(vSourceFileConfig.TEMPLATE_TABLE_NAME,'NULL');
            END IF;
            CLOSE cColumnFormat;
         END;
      END IF;

      RETURN vMsgTmp;
   EXCEPTION 

      WHEN OTHERS THEN
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));

   END GET_DET_SOURCE_FILE_CONFIG_INFO;

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

   FUNCTION GET_DET_SOURCE_FILE_RECEIVED_INFO (
       pSourceFileReceivedKey        IN   CT_MRDS.A_SOURCE_FILE_RECEIVED.A_SOURCE_FILE_RECEIVED_KEY%TYPE
      ,pIncludeConfigInfo       IN PLS_INTEGER DEFAULT 1
      ,pIncludeContainerInfo    IN PLS_INTEGER DEFAULT 1
      ,pIncludeColumnFormatInfo IN PLS_INTEGER DEFAULT 1
   ) RETURN VARCHAR2 
   ----
   -- Function to get info about File Received entry
   IS
      vSourceFileReceived CT_MRDS.A_SOURCE_FILE_RECEIVED%ROWTYPE;
      vMsgTmp VARCHAR2(32000):= '';
   BEGIN

      BEGIN
         SELECT *
          INTO vSourceFileReceived 
          FROM CT_MRDS.A_SOURCE_FILE_RECEIVED 
         WHERE A_SOURCE_FILE_RECEIVED_KEY = pSourceFileReceivedKey;

         vMsgTmp := ''
                     ||cgBL||''||'Details about received file:'
                     ||cgBL||''||'--------------------------------'
                     ||cgBL||'A_SOURCE_FILE_RECEIVED_KEY = '||vSourceFileReceived.A_SOURCE_FILE_RECEIVED_KEY
                     ||cgBL||'A_SOURCE_FILE_CONFIG_KEY   = '||vSourceFileReceived.A_SOURCE_FILE_CONFIG_KEY
                     ||cgBL||'SOURCE_FILE_NAME           = '||vSourceFileReceived.SOURCE_FILE_NAME
                     ||cgBL||'CHECKSUM                   = '||vSourceFileReceived.CHECKSUM
                     ||cgBL||'CREATED                    = '||vSourceFileReceived.CREATED
                     ||cgBL||'BYTES                      = '||vSourceFileReceived.BYTES
                     ||cgBL||'RECEPTION_DATE             = '||vSourceFileReceived.RECEPTION_DATE
                     ||cgBL||'PROCESSING_STATUS          = '||vSourceFileReceived.PROCESSING_STATUS
                     ||cgBL||'EXTERNAL_TABLE_NAME        = '||vSourceFileReceived.EXTERNAL_TABLE_NAME
                     ||cgBL||'PARTITION_YEAR             = '||vSourceFileReceived.PARTITION_YEAR
                     ||cgBL||'PARTITION_MONTH            = '||vSourceFileReceived.PARTITION_MONTH
                     ||cgBL||''||'--------------------------------'
                     ;
      EXCEPTION
         WHEN NO_DATA_FOUND THEN
         vMsgTmp := 'There is no data in A_SOURCE_FILE_RECEIVED where  A_SOURCE_FILE_RECEIVED_KEY = '||pSourceFileReceivedKey;
         RETURN vMsgTmp;
      END;

      IF pIncludeConfigInfo>0 THEN
         vMsgTmp := vMsgTmp || cgBL || CT_MRDS.FILE_MANAGER.GET_DET_SOURCE_FILE_CONFIG_INFO(vSourceFileReceived.A_SOURCE_FILE_CONFIG_KEY,pIncludeContainerInfo,pIncludeColumnFormatInfo);
      END IF;
      RETURN vMsgTmp;
   EXCEPTION 

      WHEN OTHERS THEN
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));

   END GET_DET_SOURCE_FILE_RECEIVED_INFO;

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

   FUNCTION GET_DET_USER_LOAD_OPERATIONS (
       pOperationId PLS_INTEGER
   ) RETURN VARCHAR2 
   ----
   -- Function to get info about File Received entry
   IS
      vUserLoadOperations        USER_LOAD_OPERATIONS%ROWTYPE;
      vMsgTmp VARCHAR2(32000):= '';
   BEGIN

      BEGIN
         SELECT *
           INTO vUserLoadOperations
           FROM USER_LOAD_OPERATIONS 
          WHERE id = pOperationId;

         vMsgTmp := ''
                           ||''||'Details about USER_LOAD_OPERATIONS where ID = '||pOperationId
                     ||cgBL||''||'--------------------------------'
                     ||cgBL||'ID                = '||vUserLoadOperations.ID
                     ||cgBL||'TYPE              = '||vUserLoadOperations.TYPE
                     ||cgBL||'SID               = '||vUserLoadOperations.SID
                     ||cgBL||'SERIAL#           = '||vUserLoadOperations.SERIAL#
                     ||cgBL||'START_TIME        = '||vUserLoadOperations.START_TIME
                     ||cgBL||'UPDATE_TIME       = '||vUserLoadOperations.UPDATE_TIME
                     ||cgBL||'STATUS            = '||vUserLoadOperations.STATUS
                     ||cgBL||'OWNER_NAME        = '||vUserLoadOperations.OWNER_NAME
                     ||cgBL||'TABLE_NAME        = '||vUserLoadOperations.TABLE_NAME
                     ||cgBL||'PARTITION_NAME    = '||vUserLoadOperations.PARTITION_NAME
                     ||cgBL||'SUBPARTITION_NAME = '||vUserLoadOperations.SUBPARTITION_NAME
                     ||cgBL||'FILE_URI_LIST     = '||vUserLoadOperations.FILE_URI_LIST
                     ||cgBL||'ROWS_LOADED       = '||vUserLoadOperations.ROWS_LOADED
                     ||cgBL||'LOGFILE_TABLE     = '||vUserLoadOperations.LOGFILE_TABLE
                     ||cgBL||'BADFILE_TABLE     = '||vUserLoadOperations.BADFILE_TABLE
                     ||cgBL||'STATUS_TABLE      = '||vUserLoadOperations.STATUS_TABLE
                     ||cgBL||'TEMPEXT_TABLE     = '||vUserLoadOperations.TEMPEXT_TABLE
                     ||cgBL||'CREDENTIAL_NAME   = '||vUserLoadOperations.CREDENTIAL_NAME
                     ||cgBL||'EXPIRATION_TIME   = '||vUserLoadOperations.EXPIRATION_TIME
                     ||cgBL||''||'--------------------------------'
                     ;
      EXCEPTION
         WHEN NO_DATA_FOUND THEN
         vMsgTmp := 'There is no data in USER_LOAD_OPERATIONS where ID = '||pOperationId;
         RETURN vMsgTmp;
      END;

      RETURN vMsgTmp;
   EXCEPTION 

      WHEN OTHERS THEN
         RAISE_APPLICATION_ERROR(ENV_MANAGER.CODE_UNKNOWN, ENV_MANAGER.GET_ERROR_STACK(pFormat => 'OUTPUT', pCode=> SQLCODE));

   END GET_DET_USER_LOAD_OPERATIONS;

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


--BEGIN
--   ENV_MANAGER.INIT_VARIABLES(pEnv => ENV_MANAGER.GET_DEFAULT_ENV());
END;

/
