

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Menganalisis dependensi objek untuk migrasi database sebagian dari Oracle ke PostgreSQL
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql"></a>

*Situs web, Amazon Web Services*

## Ringkasan
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-summary"></a>

Pola ini menjelaskan pentingnya mengidentifikasi dan mengelola dependensi sistem secara sistematis saat memigrasikan sebagian database Oracle ke Amazon Relational Database Service (Amazon RDS) atau Amazon Aurora PostgreSQL. Dalam migrasi sebagian, hanya subset objek database dan data dari database asli yang dimigrasikan, sedangkan database sumber terus beroperasi dan melayani aplikasi yang bergantung pada komponen yang tidak bermigrasi.

Anda harus mengidentifikasi dan menganalisis ruang lingkup migrasi saat menangani database skala besar yang memiliki aplikasi yang digabungkan erat dengan dependensi hulu dan hilir. Untuk memulai migrasi sebagian, identifikasi objek lingkup, termasuk tabel, pemicu, tampilan, prosedur tersimpan, fungsi, dan paket. Proses identifikasi ruang lingkup mengikuti pendekatan komprehensif:
+ Objek lingkup tingkat pertama diidentifikasi melalui referensi langsung dalam kode aplikasi dan pekerjaan khusus modul kritis.
+ Objek tingkat kedua diturunkan melalui analisis ketergantungan yang komprehensif.

Ketika Anda memahami bagaimana bagian-bagian yang berbeda dari sistem Anda berinteraksi, Anda dapat merencanakan urutan yang benar untuk memindahkan komponen database dengan lebih baik dan mengurangi risiko kegagalan migrasi. Tabel berikut mencantumkan berbagai jenis analisis ketergantungan.


| 
| 
| Jenis analisis | Area fokus | Tujuan | 
| --- |--- |--- |
| Ketergantungan objek | TabelTampilanProsedur TersimpanFungsiPemicu | Mengidentifikasi hubungan antara objek database dan struktur hierarkisnya | 
| Dependensi segmen | Hubungan kunci asingGantungan kunci primerReferensi lintas skema | Memetakan hubungan data dan menjaga integritas referensial | 
| Dependensi keamanan | Izin penggunaHirarki peranHak istimewa objek | Memastikan migrasi kontrol akses yang tepat dan pemeliharaan keamanan | 
| Pola akses | Operasi bacaOperasi tulis | Menentukan pola interaksi database | 

Untuk menjaga konsistensi antara sistem sumber dan target, buat mekanisme sinkronisasi data selama masa transisi. Anda juga harus memodifikasi kode aplikasi dan fungsi untuk menangani distribusi data di kedua sumber Oracle dan target database PostgreSQL.

## Prasyarat dan batasan
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-prereqs"></a>

**Prasyarat**
+ Aktif Akun AWS
+ Database Oracle (sumber)
+ Amazon RDS atau Amazon Aurora PostgreSQL (target)

**Versi produk**
+ Oracle 19c atau yang lebih baru
+ PostgreSQL 16 atau yang lebih baru

## Arsitektur
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-architecture"></a>

**Tumpukan teknologi sumber**
+ Oracle 19c atau yang lebih baru

**Tumpukan teknologi target**
+ Amazon RDS atau Amazon Aurora PostgreSQL

**Arsitektur target**

Diagram berikut menunjukkan proses migrasi dari database Oracle lokal ke Amazon RDS for Oracle, yang melibatkan hal-hal berikut:
+ Mengidentifikasi dependensi database
+ Migrasi kode database dan objek menggunakan AWS Schema Conversion Tool ()AWS SCT
+ Migrasi data menggunakan AWS Database Migration Service ()AWS DMS
+ Mereplikasi perubahan yang sedang berlangsung melalui change data capture (CDC) menggunakan AWS DMS

Untuk informasi selengkapnya, lihat [Mengintegrasikan AWS Database Migration Service dengan AWS Schema Conversion Tool](https://docs.aws.amazon.com/SchemaConversionTool/latest/userguide/CHAP_DMSIntegration.html) dalam AWS dokumentasi.

![](http://docs.aws.amazon.com/id_id/prescriptive-guidance/latest/patterns/images/pattern-img/90160825-3199-4382-95a8-ad63139c5c89/images/b09c36a4-27fa-412e-877e-57a31bcce0dc.png)


## Alat
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-tools"></a>

**Layanan AWS**
+ [Amazon Relational Database Service (Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Oracle.html)) untuk Oracle membantu Anda mengatur, mengoperasikan, dan menskalakan database relasional Oracle di. AWS Cloud
+ Amazon Aurora adalah mesin database relasional yang dikelola sepenuhnya yang dibangun untuk cloud dan kompatibel dengan MySQL dan PostgreSQL.
+ AWS Schema Conversion Tool (AWS SCT) mendukung migrasi database heterogen dengan secara otomatis mengonversi skema basis data sumber dan sebagian besar kode kustom ke format yang kompatibel dengan database target.
+ [AWS Database Migration Service (AWS DMS)](https://docs.aws.amazon.com/dms/latest/userguide/Welcome.html) membantu Anda memigrasikan penyimpanan data ke dalam AWS Cloud atau di antara kombinasi pengaturan cloud dan lokal.

**Layanan lainnya**
+ [Oracle SQL Developer](https://www.oracle.com/database/technologies/appdev/sqldeveloper-landing.html) adalah lingkungan pengembangan terintegrasi yang menyederhanakan pengembangan dan pengelolaan database Oracle baik dalam penerapan tradisional maupun berbasis cloud. Untuk pola ini, Anda dapat menggunakan [SQL\* Plus](https://docs.oracle.com/cd/B19306_01/server.102/b14357/qstart.htm).

## Praktik terbaik
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-best-practices"></a>

Untuk praktik terbaik tentang penyediaan dan migrasi database Oracle, lihat [Praktik terbaik untuk bermigrasi ke Amazon RDS for](https://docs.aws.amazon.com/prescriptive-guidance/latest/migration-oracle-database/best-practices.html) Oracle.

## Epik
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-epics"></a>

### Identifikasi dependensi objek
<a name="identify-object-dependencies"></a>


| Tugas | Deskripsi | Keterampilan yang dibutuhkan | 
| --- | --- | --- | 
| Buat tabel objek. | Identifikasi objek yang penting untuk fungsionalitas aplikasi, dan buat tabel bernama`DEPENDENT_ANALYSIS_BASELINE`. Tambahkan catatan untuk setiap objek ke tabel. Sebagai contoh, lihat bagian *Informasi tambahan*. | Insinyur data, DBA | 
| Buat prosedur database. | Buat prosedur tersimpan bernama `sp_object_dependency_analysis` untuk menganalisis dependensi objek di kedua arah (maju dan mundur) dengan menggunakan data dari tabel. `DBA_DEPENDENCIES` Sebagai contoh, lihat bagian *Informasi tambahan*. | Insinyur data, DBA | 
| Jalankan prosedurnya. | Jalankan skrip di setiap tingkat berturut-turut sampai tidak ada dependensi objek baru yang ditemukan. Semua dependensi dan level disimpan dalam tabel. `DEPENDENT_ANALYSIS_BASELINE` | DBA, Insinyur data | 

### Buat prosedur untuk dependensi tingkat segmen
<a name="create-a-procedure-for-segment-level-dependencies"></a>


| Tugas | Deskripsi | Keterampilan yang dibutuhkan | 
| --- | --- | --- | 
| Buat tabel ketergantungan. | Buat tabel dependensi tingkat segmen bernama. `REFERENTIAL_ANALYSIS_BASELINE` Ketika semua dependensi tingkat objek ditemukan, periksa tabel induk dengan menanyakan tabel. `DEPENDENT_ANALYSIS_BASELINE` `DBA_CONSTRAINT`<br />Kecualikan dependensi di mana tabel dasar direferensikan oleh tabel lain. Penimbunan ulang menangani hubungan ini. Berikut ini adalah contoh skrip:<pre>CREATE TABLE REFERENTIAL_ANALYSIS_BASELINE<br />(CHILD_OWNER VARCHAR2(50 BYTE),<br />CHILD_NAME VARCHAR2(100 BYTE),<br />PARENT_OWNER VARCHAR2(50 BYTE),<br />PARENT_NAME VARCHAR2(50 BYTE),<br />REFERENCE_PATH VARCHAR2(1000 BYTE));</pre> | Insinyur data, DBA | 
| Buat prosedur database. | Buat prosedur yang disebut`SP_OBJECT_REFERENTIAL_ANALYSIS`, dan hasilkan analisis referensial untuk semua objek yang diidentifikasi. Sebagai contoh, lihat bagian *Informasi tambahan*. | Insinyur data, DBA | 
| Jalankan prosedurnya. | Jalankan prosedur untuk mendapatkan dependensi referensial. Hasilkan detail objek analisis referensial di`REFERENTIAL_ANALYSIS_BASELINE`. | Insinyur data, DBA | 

### Identifikasi objek yang membaca dan menulis
<a name="identify-objects-that-read-and-write"></a>


| Tugas | Deskripsi | Keterampilan yang dibutuhkan | 
| --- | --- | --- | 
| Buat tabel untuk membaca dan menulis objek. | Gunakan skrip berikut untuk membuat tabel objek baca bernama `TABLE_READ_OBJECT_DETAILS` dan tabel objek tulis bernama`TABLE_WRITE_OBJECT_DETAILS`:<pre>CREATE TABLE TABLE_READ_OBJECT_DETAILS<br />(OWNER VARCHAR2(50 BYTE),<br />TAB_NAME VARCHAR2(50 BYTE),<br />READER_OWNER VARCHAR2(50 BYTE),<br />READER_NAME VARCHAR2(50 BYTE),<br />READER_TYPE VARCHAR2(50 BYTE));</pre><pre>CREATE TABLE TABLE_WRITE_OBJECT_DETAILS<br />(TABLE_NAME VARCHAR2(100 BYTE),<br />WRITEOBJ_OWNER VARCHAR2(100 BYTE),<br />WRITEOBJ_NAME VARCHAR2(100 BYTE),<br />WRITEOBJ_TYPE VARCHAR2(100 BYTE),<br />LINE VARCHAR2(100 BYTE),<br />TEXT VARCHAR2(4000 BYTE),<br />OWNER VARCHAR2(50 BYTE));</pre> | Insinyur data, DBA | 
| Buat prosedur untuk analisis. | Buat prosedur `SP_READER_OBJECTS_ANALYSIS` dan `SP_WRITER_OBJECTS_ANALYSIS` untuk menganalisis objek baca dan tulis objek, masing-masing. Prosedur ini menggunakan pencocokan pola untuk menemukan objek terkait. Sebagai contoh, lihat bagian *Informasi tambahan*. | Insinyur data, DBA | 
| Jalankan prosedurnya. | Jalankan prosedur ini untuk mengidentifikasi objek dependen. | DBA, Insinyur data | 

### Tinjau hak istimewa basis data
<a name="review-database-privileges"></a>


| Tugas | Deskripsi | Keterampilan yang dibutuhkan | 
| --- | --- | --- | 
| Buat tabel untuk meninjau hak istimewa. | Buat tabel untuk menganalisis hak istimewa bernama`OBJECT_PRIVS_ANALYSIS`. Untuk menangkap hak istimewa objek secara rekursif dalam `DEPENDENT_ANALYSIS_BASELINE` tabel, gunakan skrip berikut:<pre>CREATE TABLE OBJECT_PRIVS_ANALYSIS<br />(OWNER VARCHAR2(50 BYTE),<br />OBJECT_NAME VARCHAR2(50 BYTE),<br />USER_NAME VARCHAR2(50 BYTE),<br />PRIVS VARCHAR2(50 BYTE));</pre> | Insinyur data, DBA | 
| Buat prosedur untuk meninjau hak istimewa. | Buat prosedur bernama`SP_OBJECT_PRIVS_ANALYSIS`. Hasilkan analisis hak istimewa untuk objek yang diidentifikasi. Sebagai contoh, lihat bagian *Informasi tambahan*. | DBA, Insinyur data | 
| Jalankan prosedurnya. | Jalankan prosedur untuk menangkapnya di `OBJECT_PRIVS_ANALYSIS` tabel. | DBA, Insinyur data | 

## Pemecahan masalah
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-troubleshooting"></a>


| Isu | Solusi | 
| --- | --- | 
| Tidak dapat mengakses tabel kamus | Pastikan bahwa pengguna yang membuat objek analisis dapat mengakses tabel DBA. | 

## Sumber daya terkait
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-resources"></a>

**Dokumentasi AWS**
+ [Dokumentasi Amazon RDS dan Aurora](https://docs.aws.amazon.com/rds/)
+ [Basis data Oracle 19c ke buku pedoman migrasi Amazon Aurora PostgreSQL](https://docs.aws.amazon.com/dms/latest/oracle-to-aurora-postgresql-migration-playbook/chap-oracle-aurora-pg.html)
+ [Apa itu AWS Database Migration Service?](https://docs.aws.amazon.com/dms/latest/userguide/)
+ [Apa itu AWS Schema Conversion Tool?](https://docs.aws.amazon.com/SchemaConversionTool/latest/userguide/)

**Dokumentasi lainnya**
+ [Objek database Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Database-Objects.html)

## Informasi tambahan
<a name="multilevel-object-analysis-for-database-migration-from-oracle-to-postgresql-additional"></a>

**Script untuk `DEPENDENT_ANALYSIS_BASELINE`**

```
CREATE TABLE DEPENDENT_ANALYSIS_BASELINE
(OWNER VARCHAR2(128 BYTE) NOT NULL ENABLE,
OBJECT_NAME VARCHAR2(128 BYTE) NOT NULL ENABLE,
OBJECT_TYPE VARCHAR2(20 BYTE),
DEPEDNCY_LEVEL NUMBER,
PROJECT_NEED VARCHAR2(20 BYTE),
CATAGORY VARCHAR2(4000 BYTE),
COMMENTS VARCHAR2(4000 BYTE),
CATAGORY1 CLOB,
COMMENTS1 CLOB,
CUSTOMER_COMMENTS VARCHAR2(1000 BYTE),
BACKFILL_TO_GUS VARCHAR2(1000 BYTE),
BACKFILL_NEAR_REAL_TIME_OR_BATCH VARCHAR2(1000 BYTE),
PK_EXISTS VARCHAR2(3 BYTE),
UI_EXISTS VARCHAR2(3 BYTE),
LOB_EXISTS VARCHAR2(3 BYTE),
MASTER_LINK VARCHAR2(100 BYTE),
CONSTRAINT PK_DEPENDENT_ANALYSIS_BASELINE PRIMARY KEY (OWNER,OBJECT_NAME,OBJECT_TYPE));
```

**Prosedur untuk `SP_WRITER_OBJECTS_ANALYSIS`**

```
CREATE OR REPLACE PROCEDURE SP_WRITER_OBJECTS_ANALYSIS IS
BEGIN
  EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_WRITE_OBJECT_DETAILS';
  FOR I IN (SELECT OWNER, OBJECT_NAME FROM DEPENDENT_ANALYSIS_BASELINE WHERE OBJECT_TYPE = 'TABLE')
  LOOP
    INSERT INTO TABLE_WRITE_OBJECT_DETAILS(OWNER, TABLE_NAME, WRITEOBJ_OWNER, WRITEOBJ_NAME, WRITEOBJ_TYPE, LINE, TEXT)
    SELECT DISTINCT I.OWNER, I.OBJECT_NAME, OWNER WRITEOBJ_OWNER, NAME, TYPE, LINE, TRIM(TEXT)
    FROM DBA_SOURCE 
    WHERE UPPER(TEXT) LIKE '%' || I.OBJECT_NAME || '%'
      AND (UPPER(TEXT) LIKE '%INSERT%' || I.OBJECT_NAME || '%' 
        OR UPPER(TEXT) LIKE '%UPDATE%' || I.OBJECT_NAME || '%' 
        OR UPPER(TEXT) LIKE '%DELETE%' || I.OBJECT_NAME || '%' 
        OR UPPER(TEXT) LIKE '%UPSERT%' || I.OBJECT_NAME || '%' 
        OR UPPER(TEXT) LIKE '%MERGE%' || I.OBJECT_NAME || '%') 
      AND UPPER(TEXT) NOT LIKE '%PROCEDURE%' 
      AND UPPER(TEXT) NOT LIKE 'PROCEDURE%' 
      AND UPPER(TEXT) NOT LIKE '%FUNCTION%' 
      AND UPPER(TEXT) NOT LIKE 'FUNCTION%'
      AND UPPER(TEXT) NOT LIKE '%TRIGGER%' 
      AND UPPER(TEXT) NOT LIKE 'TRIGGER%' 
      AND UPPER(TRIM(TEXT)) NOT LIKE '%AFTER UPDATE%' 
      AND UPPER(TRIM(TEXT)) NOT LIKE 'BEFORE UPDATE%' 
      AND UPPER(TRIM(TEXT)) NOT LIKE 'BEFORE INSERT%' 
      AND UPPER(TRIM(TEXT)) NOT LIKE 'AFTER INSERT%' 
      AND UPPER(TRIM(TEXT)) NOT LIKE 'BEFORE DELETE%' 
      AND UPPER(TRIM(TEXT)) NOT LIKE 'AFTER DELETE%' 
      AND UPPER(TRIM(TEXT)) NOT LIKE '%GGLOGADM.GG_LOG_ERROR%' 
      AND (TRIM(TEXT) NOT LIKE '/*%' AND TRIM(TEXT) NOT LIKE '--%' ) 
      AND (OWNER, NAME, TYPE) IN (SELECT OWNER, NAME, TYPE FROM DBA_DEPENDENCIES WHERE REFERENCED_NAME = I.OBJECT_NAME);
  END LOOP;
END;
```

**Script untuk `SP_READER_OBJECTS_ANALYSIS`**

```
CREATE OR REPLACE PROCEDURE SP_READER_OBJECTS_ANALYSIS IS
BEGIN
  EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_READ_OBJECT_DETAILS';
  FOR I IN (SELECT OWNER, OBJECT_NAME FROM DEPENDENT_ANALYSIS_BASELINE WHERE OBJECT_TYPE = 'TABLE')
  LOOP
    INSERT INTO TABLE_READ_OBJECT_DETAILS
    SELECT DISTINCT i.owner, i.object_name, owner, name, type 
    FROM dba_dependencies 
    WHERE referenced_name = I.OBJECT_NAME
    AND referenced_type = 'TABLE' 
    AND type NOT IN ('SYNONYM', 'MATERIALIZED VIEW', 'VIEW') 
    AND (owner, name, type) NOT IN (
      SELECT DISTINCT owner, trigger_name, 'TRIGGER' 
      FROM dba_triggers 
      WHERE table_name = I.OBJECT_NAME 
      AND table_owner = i.owner
      UNION ALL
      SELECT DISTINCT owner, name, type 
      FROM dba_source
      WHERE upper(text) LIKE '%' || I.OBJECT_NAME || '%' 
      AND (upper(text) LIKE '%INSERT %' || I.OBJECT_NAME || '%' 
        OR upper(text) LIKE '%UPDATE% ' || I.OBJECT_NAME || '%' 
        OR upper(text) LIKE '%DELETE %' || I.OBJECT_NAME || '%' 
        OR upper(text) LIKE '%UPSERT %' || I.OBJECT_NAME || '%' 
        OR upper(text) LIKE '%MERGE %' || I.OBJECT_NAME || '%') 
      AND upper(text) NOT LIKE '%PROCEDURE %' 
      AND upper(text) NOT LIKE 'PROCEDURE %'
      AND upper(text) NOT LIKE '%FUNCTION %' 
      AND upper(text) NOT LIKE 'FUNCTION %'
      AND upper(text) NOT LIKE '%TRIGGER %'
      AND upper(text) NOT LIKE 'TRIGGER %'
      AND upper(trim(text)) NOT LIKE 'BEFORE INSERT %'
      AND upper(trim(text)) NOT LIKE 'BEFORE UPDATE %' 
      AND upper(trim(text)) NOT LIKE 'BEFORE DELETE %' 
      AND upper(trim(text)) NOT LIKE 'AFTER INSERT %' 
      AND upper(trim(text)) NOT LIKE 'AFTER UPDATE %' 
      AND upper(trim(text)) NOT LIKE 'AFTER DELETE %' 
      AND (trim(text) NOT LIKE '/*%' AND trim(text) NOT LIKE '--%'));
  END LOOP;
END;
```

**Script untuk `SP_OBJECT_REFERENTIAL_ANALYSIS`**

```
CREATE OR REPLACE PROCEDURE SP_OBJECT_REFERENTIAL_ANALYSIS IS
BEGIN
  EXECUTE IMMEDIATE 'TRUNCATE TABLE REFERENTIAL_ANALYSIS_BASELINE';
  INSERT INTO REFERENTIAL_ANALYSIS_BASELINE
  WITH rel AS (
    SELECT DISTINCT c.owner, c.table_name, c.r_owner r_owner,
      (SELECT table_name FROM dba_constraints 
       WHERE constraint_name = c.r_constraint_name 
       AND owner = c.r_owner) r_table_name 
    FROM dba_constraints c 
    WHERE constraint_type = 'R' 
    AND c.owner NOT IN (SELECT username FROM dba_users WHERE oracle_maintained = 'Y')
    AND c.r_owner NOT IN (SELECT username FROM dba_users WHERE oracle_maintained = 'Y')),
  tab_list AS (
    SELECT OWNER, object_name 
    FROM DEPENDENT_ANALYSIS_BASELINE 
    WHERE UPPER(OBJECT_TYPE) = 'TABLE')
  SELECT DISTINCT owner child_owner, table_name child, r_owner parent_owner,
    r_table_name parent, SYS_CONNECT_BY_PATH(r_table_name, ' -> ') || ' -> ' || table_name PATH
  FROM rel 
  START WITH (r_owner, r_table_name) IN (SELECT * FROM tab_list)
  CONNECT BY NOCYCLE (r_owner, r_table_name) = ((PRIOR owner, PRIOR table_name))
  UNION
  SELECT DISTINCT owner child_owner, table_name child, r_owner parent_owner,
    r_table_name parent, SYS_CONNECT_BY_PATH(table_name, ' -> ') || ' -> ' || r_table_name PATH
  FROM rel 
  START WITH (owner, table_name) IN (SELECT * FROM tab_list)
  CONNECT BY NOCYCLE (owner, table_name) = ((PRIOR r_owner, PRIOR r_table_name));
END;
```

**Script untuk `SP_OBJECT_PRIVS_ANALYSIS`**

```
CREATE OR REPLACE PROCEDURE SP_OBJECT_PRIVS_ANALYSIS IS
  V_SQL VARCHAR2(4000);
  V_CNT NUMBER;
BEGIN
  V_SQL := 'TRUNCATE TABLE OBJECT_PRIVS_ANALYSIS';
  EXECUTE IMMEDIATE V_SQL;
  FOR I IN (SELECT OWNER, OBJECT_NAME FROM DEPENDENT_ANALYSIS_BASELINE WHERE OBJECT_TYPE = 'TABLE')
  LOOP
    INSERT INTO OBJECT_PRIVS_ANALYSIS(OWNER, OBJECT_NAME, USER_NAME, PRIVS)
    WITH obj_to_role AS (
      SELECT DISTINCT GRANTEE role_name, 
        DECODE(privilege, 'SELECT', 'READ', 'REFERENCE', 'READ', 'INSERT', 'WRITE', 
               'UPDATE', 'WRITE', 'DELETE', 'WRITE', privilege) privs
      FROM DBA_TAB_PRIVS t, DBA_ROLES r 
      WHERE OWNER = I.OWNER 
      AND TYPE = 'TABLE' 
      AND TABLE_NAME = I.OBJECT_NAME 
      AND t.GRANTEE = r.ROLE 
      AND r.ROLE IN (SELECT ROLE FROM DBA_ROLES WHERE ORACLE_MAINTAINED = 'N')
    )
    SELECT I.OWNER, I.OBJECT_NAME, grantee, privs 
    FROM (
      -- Recursively Role to User mapping with privilege
      SELECT DISTINCT grantee, privs 
      FROM (SELECT rp.granted_role, rp.grantee, privs,
        (SELECT DECODE(COUNT(*), 0, 'ROLE', 'USER') 
         FROM (SELECT 'User' FROM DBA_users WHERE username = rp.GRANTEE)) grantee_type 
        FROM DBA_role_privs rp, obj_to_role r 
        WHERE rp.granted_role = r.role_name 
        AND grantee IN ((SELECT USERNAME FROM DBA_USERS WHERE ORACLE_MAINTAINED = 'N') 
                       UNION (SELECT ROLE FROM DBA_ROLES WHERE ORACLE_MAINTAINED = 'N'))
        AND granted_role IN (SELECT ROLE FROM DBA_ROLES WHERE ORACLE_MAINTAINED = 'N') 
        START WITH granted_role IN (SELECT DISTINCT role_name FROM obj_to_role) 
        CONNECT BY granted_role = PRIOR grantee) 
      WHERE grantee_type = 'USER'
    )
    UNION
    (
      -- Direct Object grants to User
      SELECT I.OWNER, I.OBJECT_NAME, GRANTEE, 
        DECODE(privilege, 'SELECT', 'READ', 'REFERENCE', 'READ', 'INSERT', 'WRITE',
               'UPDATE', 'WRITE', 'DELETE', 'WRITE', privilege) privs 
      FROM DBA_TAB_PRIVS, DBA_USERS 
      WHERE GRANTEE = USERNAME 
      AND OWNER = I.OWNER 
      AND TYPE = 'TABLE' 
      AND TABLE_NAME = I.OBJECT_NAME
    ) 
    ORDER BY 2 DESC;
  END LOOP;
END;
```

**Prosedur untuk `SP_OBJECT_DEPENDENCY_ANALYSIS`**

```
CREATE OR REPLACE PROCEDURE SP_OBJECT_DEPENDENCY_ANALYSIS (v_level NUMBER) IS
  TYPE typ IS RECORD (
    schema VARCHAR2(100),
    obj_type VARCHAR2(100),
    obj_name VARCHAR2(100),
    path VARCHAR2(5000)
  );
  TYPE array IS TABLE OF typ;
  l_data array;
  c SYS_REFCURSOR;
  l_errors NUMBER;
  l_errno NUMBER;
  l_msg VARCHAR2(4000);
  l_idx NUMBER;
  l_level NUMBER;
BEGIN
  l_level := v_level + 1;
  OPEN c FOR 
    WITH obj_list AS (
      SELECT owner schema_name, object_type, object_name 
      FROM DEPENDENT_ANALYSIS_BASELINE 
      WHERE depedncy_level = v_level
    ),
    fw_dep_objects AS (
      SELECT level lvl, owner, name, type, referenced_owner, referenced_name,
        referenced_type, SYS_CONNECT_BY_PATH(name, ' -> ') || ' -> ' || referenced_name PATH 
      FROM dba_dependencies
      START WITH (owner, CASE WHEN type = 'PACKAGE BODY' THEN 'PACKAGE' ELSE type END, name) 
        IN (SELECT schema_name, object_type, object_name FROM obj_list)
      CONNECT BY NOCYCLE (owner, type, name) = 
        ((PRIOR referenced_owner, PRIOR referenced_type, PRIOR referenced_name))
    ),
    bw_dep_objects AS (
      SELECT level lvl, owner, name, type, referenced_owner, referenced_name,
        referenced_type, SYS_CONNECT_BY_PATH(name, ' <- ') || ' <- ' || referenced_name PATH 
      FROM dba_dependencies
      START WITH (referenced_owner, CASE WHEN referenced_type = 'PACKAGE BODY' THEN 'PACKAGE' 
        ELSE referenced_type END, referenced_name) IN (SELECT schema_name, object_type, object_name FROM obj_list)
      CONNECT BY NOCYCLE (referenced_owner, referenced_type, referenced_name) = 
        ((PRIOR owner, PRIOR type, PRIOR name))
    )
    SELECT * FROM (
      (SELECT DISTINCT referenced_owner schema, referenced_type obj_type, 
        referenced_name obj_name, path FROM fw_dep_objects)
      UNION
      (SELECT DISTINCT owner schema, type obj_type, name obj_name, path 
       FROM bw_dep_objects)
    )
    WHERE schema IN (SELECT username FROM all_users WHERE oracle_maintained = 'N')
    ORDER BY obj_type;

  LOOP
    FETCH c BULK COLLECT INTO l_data LIMIT 100;
    BEGIN
      FORALL i IN 1..l_data.count SAVE EXCEPTIONS
        INSERT INTO DEPENDENT_ANALYSIS_BASELINE (
          owner, object_name, object_type, catagory, depedncy_level, project_need, comments
        ) 
        VALUES (
          l_data(i).schema, 
          l_data(i).obj_name,
          CASE WHEN l_data(i).obj_type = 'PACKAGE BODY' THEN 'PACKAGE' ELSE l_data(i).obj_type END,
          'level ' || l_level || ' dependency',
          l_level,
          '',
          'from dependency proc' || l_data(i).path
        );
    EXCEPTION
      WHEN OTHERS THEN
        l_errors := sql%bulk_exceptions.count;
        FOR i IN 1..l_errors LOOP
          l_errno := sql%bulk_exceptions(i).error_code;
          l_msg := SQLERRM(-l_errno);
          l_idx := sql%bulk_exceptions(i).error_index;
          UPDATE DEPENDENT_ANALYSIS_BASELINE 
          SET catagory1 = catagory1 || ', found in level' || l_level || ' dependent of ' || l_data(l_idx).path,
              comments1 = comments1 || ', from dependency proc exception ' || l_data(i).path
          WHERE owner = l_data(l_idx).schema 
          AND object_name = l_data(l_idx).obj_name 
          AND object_type = l_data(l_idx).obj_type;
        END LOOP;
    END;
    EXIT WHEN c%NOTFOUND;
  END LOOP;
  CLOSE c;
END;
```