-- =====================================================================================
-- Script: 01_MARS_1005_export_top_data.sql
-- Purpose: Export OU_TOP historical data to ODS bucket (DATA bucket, CSV format)
-- Author: Grzegorz Michalski
-- Created: 2026-03-06
-- MARS Issue: MARS-1005
-- Target: mrds_data_dev/ODS/TOP/
-- Tables:
--   1. OU_TOP.LEGACY_ALLOTMENT                       -> ODS/TOP/TOP_ALLOTMENT
--   2. OU_TOP.LEGACY_ALLOTMENT_MODIFICATION_HEADER   -> ODS/TOP/TOP_ALLOTMENT_MODIFICATION_HEADER
--   3. OU_TOP.LEGACY_ALLOTMENT_MODIFICATION_ITEM     -> ODS/TOP/TOP_ALLOTMENT_MODIFICATION_ITEM
--   4. OU_TOP.LEGACY_ANNOUNCEMENT                    -> ODS/TOP/TOP_ANNOUNCEMENT
--   5. OU_TOP.LEGACY_FBL_ITEM                        -> ODS/TOP/TOP_FULLBIDLIST_ITEM
--   6. OU_TOP.LEGACY_FULLBID_ARRAY_COMPILED          -> ODS/TOP/TOP_FULLBID_ARRAY_COMPILED
-- =====================================================================================

SET SERVEROUTPUT ON SIZE UNLIMITED;
SET TIMING ON;

PROMPT =====================================================================================
PROMPT MARS-1005: OU_TOP Historical Data Export
PROMPT =====================================================================================
PROMPT Export Strategy:
PROMPT - Source: OU_TOP schema tables (operational database)
PROMPT - Target: DATA/ODS bucket as CSV files
PROMPT - Method: DATA_EXPORTER.EXPORT_TABLE_DATA
PROMPT - Registration: Files registered in A_SOURCE_FILE_RECEIVED
PROMPT - Path Structure: ODS/TOP/TOP_*/
PROMPT Tables (6):
PROMPT   ALLOTMENT, ALLOTMENT_MODIFICATION_HEADER, ALLOTMENT_MODIFICATION_ITEM,
PROMPT   ANNOUNCEMENT, FBL_ITEM (->TOP_FULLBIDLIST_ITEM), FULLBID_ARRAY_COMPILED
PROMPT =====================================================================================

-- Log export start
INSERT INTO CT_MRDS.A_PROCESS_LOG (PROCESS_NAME, PROCEDURE_NAME, LOG_LEVEL, LOG_MESSAGE, PROCEDURE_PARAMETERS)
VALUES ('MARS-1005', 'EXPORT_TOP_DATA', 'INFO', 'Starting historical OU_TOP data export',
        'Tables: ALLOTMENT, ALLOTMENT_MODIFICATION_HEADER, ALLOTMENT_MODIFICATION_ITEM, ANNOUNCEMENT, FBL_ITEM, FULLBID_ARRAY_COMPILED');

PROMPT 
PROMPT =====================================================================================
PROMPT PRE-EXPORT CHECK: Verify Existing Files in ODS Bucket
PROMPT =====================================================================================

-- Helper procedure (inline) to check one folder
-- Check 1: ALLOTMENT
DECLARE
    vFileCount   NUMBER := 0;
    vRecordCount NUMBER := 0;
    vLocationUri VARCHAR2(1000);
    vPrintCount  NUMBER := 0;
BEGIN
    vLocationUri := CT_MRDS.FILE_MANAGER.GET_BUCKET_URI('DATA') || 'ODS/TOP/TOP_ALLOTMENT/';
    SELECT COUNT(*) INTO vFileCount
    FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri))
    WHERE object_name NOT LIKE '%/';
    IF vFileCount > 0 THEN
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: TOP_ALLOTMENT files already exist in DATA bucket');
        DBMS_OUTPUT.PUT_LINE('Location: ' || vLocationUri || '  Files found: ' || vFileCount);
        FOR rec IN (SELECT object_name, bytes FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri)) WHERE object_name NOT LIKE '%/' ORDER BY object_name) LOOP
            DBMS_OUTPUT.PUT_LINE('  - ' || rec.object_name || ' (' || rec.bytes || ' bytes)');
            vPrintCount := vPrintCount + 1;
            EXIT WHEN vPrintCount >= 10;
        END LOOP;
        IF vFileCount > 10 THEN
            DBMS_OUTPUT.PUT_LINE('  ... and ' || (vFileCount - 10) || ' more file(s)');
        END IF;
        BEGIN
            EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_ODS' INTO vRecordCount;
            DBMS_OUTPUT.PUT_LINE('>>> Records via external table: ' || vRecordCount);
        EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('WARNING: Cannot count via external table: ' || SQLERRM);
        END;
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
    ELSE
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: No existing TOP_ALLOTMENT files found - bucket is clean');
    END IF;
END;
/

-- Check 2: ALLOTMENT_MODIFICATION_HEADER
DECLARE
    vFileCount   NUMBER := 0;
    vRecordCount NUMBER := 0;
    vLocationUri VARCHAR2(1000);
    vPrintCount  NUMBER := 0;
BEGIN
    vLocationUri := CT_MRDS.FILE_MANAGER.GET_BUCKET_URI('DATA') || 'ODS/TOP/TOP_ALLOTMENT_MODIFICATION_HEADER/';
    SELECT COUNT(*) INTO vFileCount
    FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri))
    WHERE object_name NOT LIKE '%/';
    IF vFileCount > 0 THEN
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: TOP_ALLOTMENT_MODIFICATION_HEADER files already exist in DATA bucket');
        DBMS_OUTPUT.PUT_LINE('Location: ' || vLocationUri || '  Files found: ' || vFileCount);
        FOR rec IN (SELECT object_name, bytes FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri)) WHERE object_name NOT LIKE '%/' ORDER BY object_name) LOOP
            DBMS_OUTPUT.PUT_LINE('  - ' || rec.object_name || ' (' || rec.bytes || ' bytes)');
            vPrintCount := vPrintCount + 1;
            EXIT WHEN vPrintCount >= 10;
        END LOOP;
        IF vFileCount > 10 THEN
            DBMS_OUTPUT.PUT_LINE('  ... and ' || (vFileCount - 10) || ' more file(s)');
        END IF;
        BEGIN
            EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_MODIFICATION_HEADER_ODS' INTO vRecordCount;
            DBMS_OUTPUT.PUT_LINE('>>> Records via external table: ' || vRecordCount);
        EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('WARNING: Cannot count via external table: ' || SQLERRM);
        END;
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
    ELSE
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: No existing TOP_ALLOTMENT_MODIFICATION_HEADER files found - bucket is clean');
    END IF;
END;
/

-- Check 3: ALLOTMENT_MODIFICATION_ITEM
DECLARE
    vFileCount   NUMBER := 0;
    vRecordCount NUMBER := 0;
    vLocationUri VARCHAR2(1000);
    vPrintCount  NUMBER := 0;
BEGIN
    vLocationUri := CT_MRDS.FILE_MANAGER.GET_BUCKET_URI('DATA') || 'ODS/TOP/TOP_ALLOTMENT_MODIFICATION_ITEM/';
    SELECT COUNT(*) INTO vFileCount
    FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri))
    WHERE object_name NOT LIKE '%/';
    IF vFileCount > 0 THEN
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: TOP_ALLOTMENT_MODIFICATION_ITEM files already exist in DATA bucket');
        DBMS_OUTPUT.PUT_LINE('Location: ' || vLocationUri || '  Files found: ' || vFileCount);
        FOR rec IN (SELECT object_name, bytes FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri)) WHERE object_name NOT LIKE '%/' ORDER BY object_name) LOOP
            DBMS_OUTPUT.PUT_LINE('  - ' || rec.object_name || ' (' || rec.bytes || ' bytes)');
            vPrintCount := vPrintCount + 1;
            EXIT WHEN vPrintCount >= 10;
        END LOOP;
        IF vFileCount > 10 THEN
            DBMS_OUTPUT.PUT_LINE('  ... and ' || (vFileCount - 10) || ' more file(s)');
        END IF;
        BEGIN
            EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_MODIFICATION_ITEM_ODS' INTO vRecordCount;
            DBMS_OUTPUT.PUT_LINE('>>> Records via external table: ' || vRecordCount);
        EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('WARNING: Cannot count via external table: ' || SQLERRM);
        END;
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
    ELSE
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: No existing TOP_ALLOTMENT_MODIFICATION_ITEM files found - bucket is clean');
    END IF;
END;
/

-- Check 4: ANNOUNCEMENT
DECLARE
    vFileCount   NUMBER := 0;
    vRecordCount NUMBER := 0;
    vLocationUri VARCHAR2(1000);
    vPrintCount  NUMBER := 0;
BEGIN
    vLocationUri := CT_MRDS.FILE_MANAGER.GET_BUCKET_URI('DATA') || 'ODS/TOP/TOP_ANNOUNCEMENT/';
    SELECT COUNT(*) INTO vFileCount
    FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri))
    WHERE object_name NOT LIKE '%/';
    IF vFileCount > 0 THEN
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: TOP_ANNOUNCEMENT files already exist in DATA bucket');
        DBMS_OUTPUT.PUT_LINE('Location: ' || vLocationUri || '  Files found: ' || vFileCount);
        FOR rec IN (SELECT object_name, bytes FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri)) WHERE object_name NOT LIKE '%/' ORDER BY object_name) LOOP
            DBMS_OUTPUT.PUT_LINE('  - ' || rec.object_name || ' (' || rec.bytes || ' bytes)');
            vPrintCount := vPrintCount + 1;
            EXIT WHEN vPrintCount >= 10;
        END LOOP;
        IF vFileCount > 10 THEN
            DBMS_OUTPUT.PUT_LINE('  ... and ' || (vFileCount - 10) || ' more file(s)');
        END IF;
        BEGIN
            EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ODS.TOP_ANNOUNCEMENT_ODS' INTO vRecordCount;
            DBMS_OUTPUT.PUT_LINE('>>> Records via external table: ' || vRecordCount);
        EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('WARNING: Cannot count via external table: ' || SQLERRM);
        END;
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
    ELSE
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: No existing TOP_ANNOUNCEMENT files found - bucket is clean');
    END IF;
END;
/

-- Check 5: FBL_ITEM (folder: TOP_FULLBIDLIST_ITEM)
DECLARE
    vFileCount   NUMBER := 0;
    vRecordCount NUMBER := 0;
    vLocationUri VARCHAR2(1000);
    vPrintCount  NUMBER := 0;
BEGIN
    vLocationUri := CT_MRDS.FILE_MANAGER.GET_BUCKET_URI('DATA') || 'ODS/TOP/TOP_FULLBIDLIST_ITEM/';
    SELECT COUNT(*) INTO vFileCount
    FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri))
    WHERE object_name NOT LIKE '%/';
    IF vFileCount > 0 THEN
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: TOP_FULLBIDLIST_ITEM files already exist in DATA bucket');
        DBMS_OUTPUT.PUT_LINE('Location: ' || vLocationUri || '  Files found: ' || vFileCount);
        FOR rec IN (SELECT object_name, bytes FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri)) WHERE object_name NOT LIKE '%/' ORDER BY object_name) LOOP
            DBMS_OUTPUT.PUT_LINE('  - ' || rec.object_name || ' (' || rec.bytes || ' bytes)');
            vPrintCount := vPrintCount + 1;
            EXIT WHEN vPrintCount >= 10;
        END LOOP;
        IF vFileCount > 10 THEN
            DBMS_OUTPUT.PUT_LINE('  ... and ' || (vFileCount - 10) || ' more file(s)');
        END IF;
        BEGIN
            EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ODS.TOP_FULLBIDLIST_ITEM_ODS' INTO vRecordCount;
            DBMS_OUTPUT.PUT_LINE('>>> Records via external table: ' || vRecordCount);
        EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('WARNING: Cannot count via external table: ' || SQLERRM);
        END;
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
    ELSE
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: No existing TOP_FULLBIDLIST_ITEM files found - bucket is clean');
    END IF;
END;
/

-- Check 6: FULLBID_ARRAY_COMPILED
DECLARE
    vFileCount   NUMBER := 0;
    vRecordCount NUMBER := 0;
    vLocationUri VARCHAR2(1000);
    vPrintCount  NUMBER := 0;
BEGIN
    vLocationUri := CT_MRDS.FILE_MANAGER.GET_BUCKET_URI('DATA') || 'ODS/TOP/TOP_FULLBID_ARRAY_COMPILED/';
    SELECT COUNT(*) INTO vFileCount
    FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri))
    WHERE object_name NOT LIKE '%/';
    IF vFileCount > 0 THEN
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: TOP_FULLBID_ARRAY_COMPILED files already exist in DATA bucket');
        DBMS_OUTPUT.PUT_LINE('Location: ' || vLocationUri || '  Files found: ' || vFileCount);
        FOR rec IN (SELECT object_name, bytes FROM TABLE(DBMS_CLOUD.LIST_OBJECTS(credential_name => 'OCI$RESOURCE_PRINCIPAL', location_uri => vLocationUri)) WHERE object_name NOT LIKE '%/' ORDER BY object_name) LOOP
            DBMS_OUTPUT.PUT_LINE('  - ' || rec.object_name || ' (' || rec.bytes || ' bytes)');
            vPrintCount := vPrintCount + 1;
            EXIT WHEN vPrintCount >= 10;
        END LOOP;
        IF vFileCount > 10 THEN
            DBMS_OUTPUT.PUT_LINE('  ... and ' || (vFileCount - 10) || ' more file(s)');
        END IF;
        BEGIN
            EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ODS.TOP_FULLBID_ARRAY_COMPILED_ODS' INTO vRecordCount;
            DBMS_OUTPUT.PUT_LINE('>>> Records via external table: ' || vRecordCount);
        EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('WARNING: Cannot count via external table: ' || SQLERRM);
        END;
        DBMS_OUTPUT.PUT_LINE('===============================================================================');
    ELSE
        DBMS_OUTPUT.PUT_LINE('PRE-EXPORT CHECK: No existing TOP_FULLBID_ARRAY_COMPILED files found - bucket is clean');
    END IF;
END;
/

PROMPT 
PROMPT =====================================================================================
PROMPT PRE-EXPORT: Verify Source and Target Table Readiness
PROMPT =====================================================================================

DECLARE
    v1Source  NUMBER := 0;  v2Source  NUMBER := 0;  v3Source  NUMBER := 0;
    v4Source  NUMBER := 0;  v5Source  NUMBER := 0;  v6Source  NUMBER := 0;
    v1Target  NUMBER := 0;  v2Target  NUMBER := 0;  v3Target  NUMBER := 0;
    v4Target  NUMBER := 0;  v5Target  NUMBER := 0;  v6Target  NUMBER := 0;
    vTotalSource NUMBER := 0;
    vTotalTarget NUMBER := 0;
    
    -- safe_count: ONLY for ODS external tables
    -- Returns 0 when no data file (ORA-29913, ORA-29400, KUP-13023); re-raises all other errors
    PROCEDURE safe_count(pSql VARCHAR2, pResult OUT NUMBER) IS
    BEGIN
        EXECUTE IMMEDIATE pSql INTO pResult;
    EXCEPTION
        WHEN OTHERS THEN
            IF SQLCODE IN (-29913, -29400) OR SQLERRM LIKE '%KUP-13023%' THEN
                pResult := 0;
            ELSE
                RAISE;
            END IF;
    END;
BEGIN
    -- Source counts (direct - if table does not exist, error propagates)
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_ALLOTMENT'                     INTO v1Source;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_ALLOTMENT_MODIFICATION_HEADER' INTO v2Source;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_ALLOTMENT_MODIFICATION_ITEM'   INTO v3Source;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_ANNOUNCEMENT'                  INTO v4Source;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_FBL_ITEM'                      INTO v5Source;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_FULLBID_ARRAY_COMPILED'        INTO v6Source;
    vTotalSource := v1Source + v2Source + v3Source + v4Source + v5Source + v6Source;

    DBMS_OUTPUT.PUT_LINE('Source table record counts (pre-export):');
    DBMS_OUTPUT.PUT_LINE('- ALLOTMENT:                       ' || v1Source);
    DBMS_OUTPUT.PUT_LINE('- ALLOTMENT_MODIFICATION_HEADER:   ' || v2Source);
    DBMS_OUTPUT.PUT_LINE('- ALLOTMENT_MODIFICATION_ITEM:     ' || v3Source);
    DBMS_OUTPUT.PUT_LINE('- ANNOUNCEMENT:                    ' || v4Source);
    DBMS_OUTPUT.PUT_LINE('- FBL_ITEM:                        ' || v5Source);
    DBMS_OUTPUT.PUT_LINE('- FULLBID_ARRAY_COMPILED:          ' || v6Source);
    DBMS_OUTPUT.PUT_LINE('- TOTAL SOURCE: ' || vTotalSource);

    -- Target external table counts
    safe_count('SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_ODS',                       v1Target);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_MODIFICATION_HEADER_ODS',   v2Target);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_MODIFICATION_ITEM_ODS',     v3Target);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_ANNOUNCEMENT_ODS',                    v4Target);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_FULLBIDLIST_ITEM_ODS',                v5Target);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_FULLBID_ARRAY_COMPILED_ODS',          v6Target);

    vTotalTarget := GREATEST(v1Target,0) + GREATEST(v2Target,0) + GREATEST(v3Target,0)
                  + GREATEST(v4Target,0) + GREATEST(v5Target,0) + GREATEST(v6Target,0);

    DBMS_OUTPUT.PUT_LINE('');
    DBMS_OUTPUT.PUT_LINE('Target external table record counts (pre-export):');
    DBMS_OUTPUT.PUT_LINE('- TOP_ALLOTMENT_ODS:                       ' || v1Target);
    DBMS_OUTPUT.PUT_LINE('- TOP_ALLOTMENT_MODIFICATION_HEADER_ODS:   ' || v2Target);
    DBMS_OUTPUT.PUT_LINE('- TOP_ALLOTMENT_MODIFICATION_ITEM_ODS:     ' || v3Target);
    DBMS_OUTPUT.PUT_LINE('- TOP_ANNOUNCEMENT_ODS:                    ' || v4Target);
    DBMS_OUTPUT.PUT_LINE('- TOP_FULLBIDLIST_ITEM_ODS:                ' || v5Target);
    DBMS_OUTPUT.PUT_LINE('- TOP_FULLBID_ARRAY_COMPILED_ODS:          ' || v6Target);

    IF vTotalSource > 0 THEN
        DBMS_OUTPUT.PUT_LINE('SUCCESS: Source tables contain data - ready for export');
    ELSE
        DBMS_OUTPUT.PUT_LINE('WARNING: Source tables exist but contain no data - export will produce empty files');
    END IF;

    IF vTotalTarget = 0 THEN
        DBMS_OUTPUT.PUT_LINE('SUCCESS: Target external tables are clean - ready for fresh export');
    ELSE
        DBMS_OUTPUT.PUT_LINE('WARNING: Target tables contain ' || vTotalTarget || ' records - may be re-run');
    END IF;

    DBMS_OUTPUT.PUT_LINE('Proceeding with export...');
END;
/

PROMPT 
PROMPT =====================================================================================
PROMPT TABLE 1/6: OU_TOP.LEGACY_ALLOTMENT -> ODS/TOP/TOP_ALLOTMENT
PROMPT =====================================================================================

BEGIN
    CT_MRDS.DATA_EXPORTER.EXPORT_TABLE_DATA(
        pSchemaName        => 'OU_TOP',
        pTableName         => 'LEGACY_ALLOTMENT',
        pKeyColumnName     => 'A_ETL_LOAD_SET_FK',  -- ETL key for data lookup
        pBucketArea        => 'ODS',
        pFolderName        => 'ODS/TOP/TOP_ALLOTMENT',
        pTemplateTableName => 'CT_ET_TEMPLATES.TOP_ALLOTMENT',
        pMaxFileSize       => 104857600,
        pRegisterExport    => TRUE,
        pProcessName       => 'MARS-1005'
    );
    DBMS_OUTPUT.PUT_LINE('SUCCESS: ALLOTMENT export completed successfully');
EXCEPTION
    WHEN OTHERS THEN
        DECLARE vErrorMsg VARCHAR2(4000) := SUBSTR(SQLERRM, 1, 4000); BEGIN
            DBMS_OUTPUT.PUT_LINE('ERROR: ALLOTMENT export failed: ' || vErrorMsg);
            INSERT INTO CT_MRDS.A_PROCESS_LOG (guid, Username, Osuser, Machine, Module, process_name, procedure_name, procedure_parameters, log_level, log_message)
            VALUES ('MARS-1005', USER, SYS_CONTEXT('USERENV','OS_USER'), SYS_CONTEXT('USERENV','HOST'),
                    'MARS-1005', 'MARS-1005', 'EXPORT_ALLOTMENT', NULL, 'ERROR', 'Export failed: ' || vErrorMsg);
            COMMIT;
        END;
END;
/

PROMPT 
PROMPT =====================================================================================
PROMPT TABLE 2/6: OU_TOP.LEGACY_ALLOTMENT_MODIFICATION_HEADER -> ODS/TOP/TOP_ALLOTMENT_MODIFICATION_HEADER
PROMPT =====================================================================================

BEGIN
    CT_MRDS.DATA_EXPORTER.EXPORT_TABLE_DATA(
        pSchemaName        => 'OU_TOP',
        pTableName         => 'LEGACY_ALLOTMENT_MODIFICATION_HEADER',
        pKeyColumnName     => 'A_ETL_LOAD_SET_FK',  -- ETL key for data lookup
        pBucketArea        => 'ODS',
        pFolderName        => 'ODS/TOP/TOP_ALLOTMENT_MODIFICATION_HEADER',
        pTemplateTableName => 'CT_ET_TEMPLATES.TOP_ALLOTMENT_MODIFICATION_HEADER',
        pMaxFileSize       => 104857600,
        pRegisterExport    => TRUE,
        pProcessName       => 'MARS-1005'
    );
    DBMS_OUTPUT.PUT_LINE('SUCCESS: ALLOTMENT_MODIFICATION_HEADER export completed successfully');
EXCEPTION
    WHEN OTHERS THEN
        DECLARE vErrorMsg VARCHAR2(4000) := SUBSTR(SQLERRM, 1, 4000); BEGIN
            DBMS_OUTPUT.PUT_LINE('ERROR: ALLOTMENT_MODIFICATION_HEADER export failed: ' || vErrorMsg);
            INSERT INTO CT_MRDS.A_PROCESS_LOG (guid, Username, Osuser, Machine, Module, process_name, procedure_name, procedure_parameters, log_level, log_message)
            VALUES ('MARS-1005', USER, SYS_CONTEXT('USERENV','OS_USER'), SYS_CONTEXT('USERENV','HOST'),
                    'MARS-1005', 'MARS-1005', 'EXPORT_ALLOTMENT_MOD_HEADER', NULL, 'ERROR', 'Export failed: ' || vErrorMsg);
            COMMIT;
        END;
END;
/

PROMPT 
PROMPT =====================================================================================
PROMPT TABLE 3/6: OU_TOP.LEGACY_ALLOTMENT_MODIFICATION_ITEM -> ODS/TOP/TOP_ALLOTMENT_MODIFICATION_ITEM
PROMPT =====================================================================================

BEGIN
    CT_MRDS.DATA_EXPORTER.EXPORT_TABLE_DATA(
        pSchemaName        => 'OU_TOP',
        pTableName         => 'LEGACY_ALLOTMENT_MODIFICATION_ITEM',
        pKeyColumnName     => 'A_ETL_LOAD_SET_FK',  -- ETL key for data lookup
        pBucketArea        => 'ODS',
        pFolderName        => 'ODS/TOP/TOP_ALLOTMENT_MODIFICATION_ITEM',
        pTemplateTableName => 'CT_ET_TEMPLATES.TOP_ALLOTMENT_MODIFICATION_ITEM',
        pMaxFileSize       => 104857600,
        pRegisterExport    => TRUE,
        pProcessName       => 'MARS-1005'
    );
    DBMS_OUTPUT.PUT_LINE('SUCCESS: ALLOTMENT_MODIFICATION_ITEM export completed successfully');
EXCEPTION
    WHEN OTHERS THEN
        DECLARE vErrorMsg VARCHAR2(4000) := SUBSTR(SQLERRM, 1, 4000); BEGIN
            DBMS_OUTPUT.PUT_LINE('ERROR: ALLOTMENT_MODIFICATION_ITEM export failed: ' || vErrorMsg);
            INSERT INTO CT_MRDS.A_PROCESS_LOG (guid, Username, Osuser, Machine, Module, process_name, procedure_name, procedure_parameters, log_level, log_message)
            VALUES ('MARS-1005', USER, SYS_CONTEXT('USERENV','OS_USER'), SYS_CONTEXT('USERENV','HOST'),
                    'MARS-1005', 'MARS-1005', 'EXPORT_ALLOTMENT_MOD_ITEM', NULL, 'ERROR', 'Export failed: ' || vErrorMsg);
            COMMIT;
        END;
END;
/

PROMPT 
PROMPT =====================================================================================
PROMPT TABLE 4/6: OU_TOP.LEGACY_ANNOUNCEMENT -> ODS/TOP/TOP_ANNOUNCEMENT
PROMPT =====================================================================================

BEGIN
    CT_MRDS.DATA_EXPORTER.EXPORT_TABLE_DATA(
        pSchemaName        => 'OU_TOP',
        pTableName         => 'LEGACY_ANNOUNCEMENT',
        pKeyColumnName     => 'A_ETL_LOAD_SET_FK',  -- ETL key for data lookup
        pBucketArea        => 'ODS',
        pFolderName        => 'ODS/TOP/TOP_ANNOUNCEMENT',
        pTemplateTableName => 'CT_ET_TEMPLATES.TOP_ANNOUNCEMENT',
        pMaxFileSize       => 104857600,
        pRegisterExport    => TRUE,
        pProcessName       => 'MARS-1005'
    );
    DBMS_OUTPUT.PUT_LINE('SUCCESS: ANNOUNCEMENT export completed successfully');
EXCEPTION
    WHEN OTHERS THEN
        DECLARE vErrorMsg VARCHAR2(4000) := SUBSTR(SQLERRM, 1, 4000); BEGIN
            DBMS_OUTPUT.PUT_LINE('ERROR: ANNOUNCEMENT export failed: ' || vErrorMsg);
            INSERT INTO CT_MRDS.A_PROCESS_LOG (guid, Username, Osuser, Machine, Module, process_name, procedure_name, procedure_parameters, log_level, log_message)
            VALUES ('MARS-1005', USER, SYS_CONTEXT('USERENV','OS_USER'), SYS_CONTEXT('USERENV','HOST'),
                    'MARS-1005', 'MARS-1005', 'EXPORT_ANNOUNCEMENT', NULL, 'ERROR', 'Export failed: ' || vErrorMsg);
            COMMIT;
        END;
END;
/

PROMPT 
PROMPT =====================================================================================
PROMPT TABLE 5/6: OU_TOP.LEGACY_FBL_ITEM -> ODS/TOP/TOP_FULLBIDLIST_ITEM
PROMPT =====================================================================================

BEGIN
    CT_MRDS.DATA_EXPORTER.EXPORT_TABLE_DATA(
        pSchemaName        => 'OU_TOP',
        pTableName         => 'LEGACY_FBL_ITEM',
        pKeyColumnName     => 'A_ETL_LOAD_SET_FK',  -- ETL key for data lookup
        pBucketArea        => 'ODS',
        pFolderName        => 'ODS/TOP/TOP_FULLBIDLIST_ITEM',
        pTemplateTableName => 'CT_ET_TEMPLATES.TOP_FULLBIDLIST_ITEM',
        pMaxFileSize       => 104857600,
        pRegisterExport    => TRUE,
        pProcessName       => 'MARS-1005'
    );
    DBMS_OUTPUT.PUT_LINE('SUCCESS: FBL_ITEM export completed successfully');
EXCEPTION
    WHEN OTHERS THEN
        DECLARE vErrorMsg VARCHAR2(4000) := SUBSTR(SQLERRM, 1, 4000); BEGIN
            DBMS_OUTPUT.PUT_LINE('ERROR: FBL_ITEM export failed: ' || vErrorMsg);
            INSERT INTO CT_MRDS.A_PROCESS_LOG (guid, Username, Osuser, Machine, Module, process_name, procedure_name, procedure_parameters, log_level, log_message)
            VALUES ('MARS-1005', USER, SYS_CONTEXT('USERENV','OS_USER'), SYS_CONTEXT('USERENV','HOST'),
                    'MARS-1005', 'MARS-1005', 'EXPORT_FBL_ITEM', NULL, 'ERROR', 'Export failed: ' || vErrorMsg);
            COMMIT;
        END;
END;
/

PROMPT 
PROMPT =====================================================================================
PROMPT TABLE 6/6: OU_TOP.LEGACY_FULLBID_ARRAY_COMPILED -> ODS/TOP/TOP_FULLBID_ARRAY_COMPILED
PROMPT =====================================================================================

BEGIN
    CT_MRDS.DATA_EXPORTER.EXPORT_TABLE_DATA(
        pSchemaName        => 'OU_TOP',
        pTableName         => 'LEGACY_FULLBID_ARRAY_COMPILED',
        pKeyColumnName     => 'A_ETL_LOAD_SET_FK',  -- ETL key for data lookup
        pBucketArea        => 'ODS',
        pFolderName        => 'ODS/TOP/TOP_FULLBID_ARRAY_COMPILED',
        pTemplateTableName => 'CT_ET_TEMPLATES.TOP_FULLBID_ARRAY_COMPILED',
        pMaxFileSize       => 104857600,
        pRegisterExport    => TRUE,
        pProcessName       => 'MARS-1005'
    );
    DBMS_OUTPUT.PUT_LINE('SUCCESS: FULLBID_ARRAY_COMPILED export completed successfully');
EXCEPTION
    WHEN OTHERS THEN
        DECLARE vErrorMsg VARCHAR2(4000) := SUBSTR(SQLERRM, 1, 4000); BEGIN
            DBMS_OUTPUT.PUT_LINE('ERROR: FULLBID_ARRAY_COMPILED export failed: ' || vErrorMsg);
            INSERT INTO CT_MRDS.A_PROCESS_LOG (guid, Username, Osuser, Machine, Module, process_name, procedure_name, procedure_parameters, log_level, log_message)
            VALUES ('MARS-1005', USER, SYS_CONTEXT('USERENV','OS_USER'), SYS_CONTEXT('USERENV','HOST'),
                    'MARS-1005', 'MARS-1005', 'EXPORT_FULLBID_ARRAY_COMPILED', NULL, 'ERROR', 'Export failed: ' || vErrorMsg);
            COMMIT;
        END;
END;
/

PROMPT 
PROMPT =====================================================================================
PROMPT Export Summary - Checking Results
PROMPT =====================================================================================

-- Log completion
INSERT INTO CT_MRDS.A_PROCESS_LOG (PROCESS_NAME, PROCEDURE_NAME, LOG_LEVEL, LOG_MESSAGE)
VALUES ('MARS-1005', 'EXPORT_TOP_DATA', 'INFO', 'All OU_TOP historical exports completed successfully');

PROMPT 
PROMPT =====================================================================================
PROMPT MARS-1005 OU_TOP Export Completed!
PROMPT =====================================================================================
PROMPT POST-EXPORT: Source vs Target Record Count Comparison
PROMPT =====================================================================================

DECLARE
    v1S NUMBER := 0; v2S NUMBER := 0; v3S NUMBER := 0;
    v4S NUMBER := 0; v5S NUMBER := 0; v6S NUMBER := 0;
    v1T NUMBER := 0; v2T NUMBER := 0; v3T NUMBER := 0;
    v4T NUMBER := 0; v5T NUMBER := 0; v6T NUMBER := 0;
    vTotalS NUMBER := 0;
    vTotalT NUMBER := 0;
    vMismatch NUMBER := 0;

    -- safe_count: ONLY for ODS external tables
    -- Returns 0 when no data file (ORA-29913, ORA-29400, KUP-13023); re-raises all other errors
    PROCEDURE safe_count(pSql VARCHAR2, pResult OUT NUMBER) IS
    BEGIN
        EXECUTE IMMEDIATE pSql INTO pResult;
    EXCEPTION
        WHEN OTHERS THEN
            IF SQLCODE IN (-29913, -29400) OR SQLERRM LIKE '%KUP-13023%' THEN
                pResult := 0;
            ELSE
                RAISE;
            END IF;
    END;

    PROCEDURE print_row(pTable VARCHAR2, pSrc NUMBER, pTgt NUMBER) IS
    BEGIN
        DBMS_OUTPUT.PUT_LINE(
            RPAD(pTable, 40) || ' | ' ||
            RPAD(TO_CHAR(pSrc), 8) || ' | ' ||
            RPAD(TO_CHAR(pTgt), 8) || ' | ' ||
            CASE WHEN pSrc = pTgt THEN 'OK' ELSE 'MISMATCH' END);
    END;
BEGIN
    -- Source (direct - if table does not exist, error propagates)
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_ALLOTMENT'                     INTO v1S;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_ALLOTMENT_MODIFICATION_HEADER' INTO v2S;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_ALLOTMENT_MODIFICATION_ITEM'   INTO v3S;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_ANNOUNCEMENT'                  INTO v4S;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_FBL_ITEM'                      INTO v5S;
    EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM OU_TOP.LEGACY_FULLBID_ARRAY_COMPILED'        INTO v6S;
    vTotalS := v1S + v2S + v3S + v4S + v5S + v6S;

    -- Target
    safe_count('SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_ODS',                       v1T);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_MODIFICATION_HEADER_ODS',   v2T);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_ALLOTMENT_MODIFICATION_ITEM_ODS',     v3T);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_ANNOUNCEMENT_ODS',                    v4T);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_FULLBIDLIST_ITEM_ODS',                v5T);
    safe_count('SELECT COUNT(*) FROM ODS.TOP_FULLBID_ARRAY_COMPILED_ODS',          v6T);
    vTotalT := v1T + v2T + v3T + v4T + v5T + v6T;

    DBMS_OUTPUT.PUT_LINE('POST-EXPORT VERIFICATION SUMMARY');
    DBMS_OUTPUT.PUT_LINE(RPAD('Table', 40) || ' | Source   | Target   | Match');
    DBMS_OUTPUT.PUT_LINE(RPAD('-', 75, '-'));
    print_row('ALLOTMENT',                       v1S, v1T); IF v1S != v1T THEN vMismatch := vMismatch + 1; END IF;
    print_row('ALLOTMENT_MODIFICATION_HEADER',   v2S, v2T); IF v2S != v2T THEN vMismatch := vMismatch + 1; END IF;
    print_row('ALLOTMENT_MODIFICATION_ITEM',     v3S, v3T); IF v3S != v3T THEN vMismatch := vMismatch + 1; END IF;
    print_row('ANNOUNCEMENT',                    v4S, v4T); IF v4S != v4T THEN vMismatch := vMismatch + 1; END IF;
    print_row('FBL_ITEM (->FULLBIDLIST_ITEM)',   v5S, v5T); IF v5S != v5T THEN vMismatch := vMismatch + 1; END IF;
    print_row('FULLBID_ARRAY_COMPILED',          v6S, v6T); IF v6S != v6T THEN vMismatch := vMismatch + 1; END IF;
    DBMS_OUTPUT.PUT_LINE(RPAD('-', 75, '-'));
    print_row('TOTAL', vTotalS, vTotalT);

    DBMS_OUTPUT.PUT_LINE('');
    IF vMismatch = 0 THEN
        DBMS_OUTPUT.PUT_LINE('SUCCESS: All record counts match - export verified');
    ELSE
        DBMS_OUTPUT.PUT_LINE('WARNING: ' || vMismatch || ' table(s) have record count mismatches');
        DBMS_OUTPUT.PUT_LINE('  Please review export logs and external table access permissions');
    END IF;
END;
/

-- Log export completion
INSERT INTO CT_MRDS.A_PROCESS_LOG (PROCESS_NAME, PROCEDURE_NAME, LOG_LEVEL, LOG_MESSAGE, PROCEDURE_PARAMETERS)
VALUES ('MARS-1005', 'EXPORT_TOP_DATA', 'INFO', 'Historical OU_TOP data export completed',
        'Check verification scripts for detailed results');

COMMIT;

PROMPT 
PROMPT =====================================================================================
PROMPT MARS-1005 OU_TOP Historical Data Export - COMPLETED
PROMPT 
PROMPT Next steps:
PROMPT 1. Run: @02_MARS_1005_verify_exports.sql (verify file registration)
PROMPT 2. Run: @03_MARS_1005_verify_data_integrity.sql (full data verification)
PROMPT =====================================================================================