-- ============================================================
-- 55_reapply_kb_vpd_after_table_reload.sql
--
-- KB 원장을 DROP/CREATE 또는 재적재한 뒤 실행한다.
-- 테이블 재생성으로 사라진 POC_2 KB VPD/CLS 정책과 CB_ORDS SELECT
-- 권한만 복구한다. 사용자·역할·권한 조건과 Bearer 토큰은 변경하지 않는다.
-- Execute as ADMIN using SQLcl.
-- ============================================================
WHENEVER SQLERROR EXIT SQL.SQLCODE
SET ECHO OFF
SET FEEDBACK ON
SET DEFINE OFF

PROMPT === 1. Validating reloaded KB table contract ===
DECLARE
  PROCEDURE require_column(p_table_name IN VARCHAR2, p_column_name IN VARCHAR2) IS
    v_count NUMBER;
  BEGIN
    SELECT COUNT(*)
    INTO v_count
    FROM all_tab_columns
    WHERE owner = 'POC_2'
      AND table_name = p_table_name
      AND column_name = p_column_name;
    IF v_count = 0 THEN
      RAISE_APPLICATION_ERROR(-20001, 'Required column is missing: POC_2.' || p_table_name || '.' || p_column_name);
    END IF;
  END;

  PROCEDURE require_runtime_object(p_object_name IN VARCHAR2, p_object_type IN VARCHAR2) IS
    v_count NUMBER;
  BEGIN
    SELECT COUNT(*)
    INTO v_count
    FROM all_objects
    WHERE owner = 'ADMIN'
      AND object_name = p_object_name
      AND object_type = p_object_type
      AND status = 'VALID';
    IF v_count = 0 THEN
      RAISE_APPLICATION_ERROR(-20002, 'Required runtime object is invalid: ADMIN.' || p_object_name);
    END IF;
  END;
BEGIN
  require_column('KB_STAKEHOLDERS', 'USER_ID');
  require_column('KB_STAKEHOLDERS', 'ROLE');
  require_column('KB_STAKEHOLDERS', 'CHANNEL');
  require_column('KB_CONTRACTS', 'CUST_ID');
  require_column('KB_CONTRACTS', 'CONTRACT_NO');
  require_column('KB_CONTRACTS', 'FC_ID');
  require_column('KB_CONTRACTS', 'FC_CHANNEL');
  require_column('KB_CUSTOMERS', 'CUST_ID');
  require_column('KB_CUSTOMERS', 'CUST_NM');
  require_column('KB_CUSTOMERS', 'RRN_MASKED');
  require_column('KB_COVERAGES', 'CUST_ID');
  require_column('KB_CLAIMS', 'CUST_ID');
  require_column('KB_CLAIMS', 'CLAIM_AMT');
  require_column('KB_CLAIMS', 'PAID_AMT');
  require_column('KB_EXTERNAL_HOLDINGS', 'CUST_ID');
  require_column('KB_EXTERNAL_HOLDINGS', 'EXT_INSURER');
  require_column('KB_EXTERNAL_HOLDINGS', 'EXT_PRODUCT_GRP');
  require_column('KB_EXTERNAL_HOLDINGS', 'EXT_PRODUCT_TYPE');

  require_runtime_object('CB_AGENT_CTX_PKG', 'PACKAGE');
  require_runtime_object('CB_AGENT_CTX_PKG', 'PACKAGE BODY');
  require_runtime_object('CB_AGENT_DOC_VPD_FILTER', 'FUNCTION');
  require_runtime_object('CB_AGENT_CAN_READ_COLUMN', 'FUNCTION');
END;
/

PROMPT === 2. Restoring CB_ORDS runtime grants ===
GRANT SELECT ON POC_2.KB_STAKEHOLDERS TO CB_ORDS;
GRANT SELECT ON POC_2.KB_CUSTOMERS TO CB_ORDS;
GRANT SELECT ON POC_2.KB_PRODUCTS TO CB_ORDS;
GRANT SELECT ON POC_2.KB_CONTRACTS TO CB_ORDS;
GRANT SELECT ON POC_2.KB_COVERAGES TO CB_ORDS;
GRANT SELECT ON POC_2.KB_CLAIMS TO CB_ORDS;
GRANT SELECT ON POC_2.KB_EXTERNAL_HOLDINGS TO CB_ORDS;
GRANT EXECUTE ON CB_AGENT_CTX_PKG TO CB_ORDS;
GRANT EXECUTE ON CB_AGENT_DOC_VPD_FILTER TO CB_ORDS;
GRANT EXECUTE ON CB_AGENT_CAN_READ_COLUMN TO CB_ORDS;

PROMPT === 3. Reapplying row VPD policies ===
DECLARE
  PROCEDURE replace_row_policy(p_object_name IN VARCHAR2) IS
    v_count NUMBER;
    v_policy_name VARCHAR2(128) := 'KB_' || p_object_name || '_ROW_POLICY';
  BEGIN
    SELECT COUNT(*)
    INTO v_count
    FROM all_policies
    WHERE object_owner = 'POC_2'
      AND object_name = p_object_name
      AND policy_name = v_policy_name;
    IF v_count > 0 THEN
      DBMS_RLS.DROP_POLICY(
        object_schema => 'POC_2',
        object_name => p_object_name,
        policy_name => v_policy_name
      );
    END IF;
    DBMS_RLS.ADD_POLICY(
      object_schema => 'POC_2',
      object_name => p_object_name,
      policy_name => v_policy_name,
      function_schema => 'ADMIN',
      policy_function => 'CB_AGENT_DOC_VPD_FILTER',
      statement_types => 'SELECT',
      policy_type => DBMS_RLS.DYNAMIC,
      enable => TRUE
    );
  END;
BEGIN
  replace_row_policy('KB_STAKEHOLDERS');
  replace_row_policy('KB_CUSTOMERS');
  replace_row_policy('KB_PRODUCTS');
  replace_row_policy('KB_CONTRACTS');
  replace_row_policy('KB_COVERAGES');
  replace_row_policy('KB_CLAIMS');
  replace_row_policy('KB_EXTERNAL_HOLDINGS');
END;
/

PROMPT === 4. Removing deprecated VPD column NULL policies ===
-- Architecture rule: VPD filters rows only. Column masking is handled solely
-- by ASO / DBMS_REDACT through 63_kb_aso_masking_rule_runtime.sql.
DECLARE
  PROCEDURE drop_column_policy(p_object_name IN VARCHAR2, p_policy_name IN VARCHAR2) IS
  BEGIN
    DBMS_RLS.DROP_POLICY(
      object_schema => 'POC_2', object_name => p_object_name, policy_name => p_policy_name
    );
  EXCEPTION
    WHEN OTHERS THEN
      -- A missing policy is already the desired state. Do not hide other errors.
      IF SQLCODE != -28102 THEN RAISE; END IF;
  END;
BEGIN
  drop_column_policy('KB_CUSTOMERS', 'KB_CUST_NM_CLS_POLICY');
  drop_column_policy('KB_CUSTOMERS', 'KB_RRN_CLS_POLICY');
  drop_column_policy('KB_CLAIMS', 'KB_CLAIM_AMT_CLS_POLICY');
  drop_column_policy('KB_CLAIMS', 'KB_PAID_AMT_CLS_POLICY');
  drop_column_policy('KB_EXTERNAL_HOLDINGS', 'KB_EXT_INSURER_CLS_POLICY');
  drop_column_policy('KB_EXTERNAL_HOLDINGS', 'KB_EXT_PRODUCT_GRP_CLS_POLICY');
  drop_column_policy('KB_EXTERNAL_HOLDINGS', 'KB_EXT_PRODUCT_TYPE_CLS_POLICY');
END;
/

PROMPT === 5. Verification ===
SELECT object_name,
       COUNT(*) AS policy_count,
       LISTAGG(policy_name, ', ') WITHIN GROUP (ORDER BY policy_name) AS policy_names
FROM all_policies
WHERE object_owner = 'POC_2'
  AND object_name IN (
    'KB_CUSTOMERS', 'KB_PRODUCTS', 'KB_CONTRACTS', 'KB_COVERAGES',
    'KB_CLAIMS', 'KB_EXTERNAL_HOLDINGS', 'KB_STAKEHOLDERS'
  )
GROUP BY object_name
ORDER BY object_name;

SELECT table_name, grantee, privilege
FROM all_tab_privs
WHERE table_schema = 'POC_2'
  AND grantee = 'CB_ORDS'
  AND privilege = 'SELECT'
  AND table_name IN (
    'KB_CUSTOMERS', 'KB_PRODUCTS', 'KB_CONTRACTS', 'KB_COVERAGES',
    'KB_CLAIMS', 'KB_EXTERNAL_HOLDINGS', 'KB_STAKEHOLDERS'
  )
ORDER BY table_name;

PROMPT === KB VPD/CLS restoration complete ===
EXIT
