[Autonomous Database]DBMS_DATAPUMPパッケージでエクスポートしてDatabase Actionsのデータ・ポンプでインポートしてみた

# はじめに
Database Actionsが付属しているAutonmous DatabaseではDBMS_DATAPUMPパッケージを使うと、Oracle Clientを準備することなくエクスポート、インポートを行うことができます。またDatabase Actionsのデータ・ポンプはDBMS_DATAPUMPパッケージを利用したジョブの監視が可能です。
ということで、Autonomous Databaseで以下を試してみました。

+ DBMS_DATAPUMPパッケージを利用してADMINスキーマをエクスポート
+ Database Actionsのデータ・ポンプでエクスポートジョブを監視、完了後のログ確認とダンプファイルのダウンロード
+ Database Actionsのデータ・ポンプのインポートでエクスポートしたADMINスキーマの表データを切り捨てでインポート
+ DBMS_DATAPUMPパッケージを使用して、Object Storageにエクスポート

**前提条件**
+ Autonomous Database Serverlessインスタンスを作成済み
+ ADMINユーザーで任意の表を作成済み
+ ADMINユーザーでObject StorageにアクセスできるようOCIユーザーを使ったクレデンシャルを作成済み(今回はCRED_ADMIN)
+ ADMINユーザーでリソース・プリンシパルを有効化済み


# 1.DBMS_DATAPUMPでディレクトリにエクスポートする
ADMINユーザでログインし、SQLで以下を実行します。出力先は事前定義されているディレクトリDATA_PUMP_DIRです。

```sql
SET serveroutput ON
SET escape off
 
DECLARE
    h1 NUMBER;
    s VARCHAR2(1000):=NULL;
    errorvarchar VARCHAR2(100):= 'ERROR';
    tryGetStatus NUMBER := 0;
    success_with_info EXCEPTION;
    PRAGMA EXCEPTION_INIT(success_with_info, -31627);
BEGIN
    h1 := dbms_datapump.OPEN (operation => 'EXPORT', job_mode => 'SCHEMA', job_name => 'EXPORT_SCHEMA_JOB', version => 'COMPATIBLE'); 
    tryGetStatus := 1;
--    dbms_datapump.set_parameter(handle => h1, name => 'COMPRESSION', VALUE => 'ALL'); 
--    dbms_datapump.set_parallel(handle => h1, degree => 1); 
    dbms_datapump.add_file(handle => h1, filename => 'EXPORT_SCHEMA_ADMIN.LOG', directory => 'DATA_PUMP_DIR', filetype => 3); 
    dbms_datapump.set_parameter(handle => h1, name => 'KEEP_MASTER', VALUE => 1); 
    dbms_datapump.metadata_filter(handle => h1, name => 'SCHEMA_EXPR', VALUE => 'IN(''ADMIN'')'); 
    dbms_datapump.add_file(handle => h1, filename => 'EXPORT_SCHEMA_ADMIN.DMP', directory => 'DATA_PUMP_DIR', filesize => '500M',  filetype => 1); 
    dbms_datapump.set_parameter(handle => h1, name => 'INCLUDE_METADATA', VALUE => 1); 
    dbms_datapump.set_parameter(handle => h1, name => 'DATA_ACCESS_METHOD', VALUE => 'AUTOMATIC'); 
    dbms_datapump.set_parameter(handle => h1, name => 'ESTIMATE', VALUE => 'BLOCKS'); 
    dbms_datapump.start_job(handle => h1, skip_current => 0, abort_step => 0); 
    dbms_datapump.detach(handle => h1); 
    errorvarchar := 'NO_ERROR'; 
EXCEPTION
    WHEN OTHERS THEN
    BEGIN 
        IF ((errorvarchar = 'ERROR')AND(tryGetStatus=1)) THEN 
            DBMS_DATAPUMP.DETACH(h1);
        END IF;
    EXCEPTION 
    WHEN OTHERS THEN 
        NULL;
    END;
    RAISE;
END;
/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/67340124-97d3-4b27-977e-6b977a0df415.png)


今回重要なのが、この一文です。正常に完了した場合にマスター表を削除するかどうかの設定です。

```dbms_datapump.set_parameter(handle => h1, name => 'KEEP_MASTER', VALUE => 1);```

デフォルトは0で正常完了後削除されてしまうので、ジョブが正常に完了した場合、Database Actionsのデータ・ポンプではジョブの実行中だけ確認できて結果が見えないという状態に陥ってしまいます。

# 2.Database Actionsのデータ・ポンプでジョブを確認する

実行後、データ・ポンプを確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/448ade8d-f1a1-4161-9a18-59ee6862bc4c.png)


実行中のジョブの情報があります。自動リフレッシュがオフなので、手動でリフレッシュをすると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/10b750cf-d48d-4efb-a9d1-b60660d142da.png)


完了になりました。完了したジョブからはダンプファイルのダウンロードやログの参照ができます。
エクスポートしたダンプファイルEXPORT_SCHEMA_ADMIN.DMPをダウンロードしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/84a58815-5262-4bb5-b465-9c7059f59549.png)

ログはダンプファイル名の下のURLのリンクを開くと確認できますが、文字化けしていたので

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/4cd7ec00-3ee2-4f30-a97c-4746def1d487.png)

ブラウザでエンコーディングをUTF8に指定するとこのように見えました。EMP,DEPTなどの表が4つエクスポートされています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/158010df-f1db-468a-a618-8f5c71cbdedd.png)


# 3.Database Actionsのデータ・ポンプでインポートする
データ・ポンプではインポートも可能です。同じAutonomous DatabaseのADMINのEMP表にデータだけをインポートしてみます。

ダンプファイルはオブジェクトストレージ上にある必要があるため、ダウンロードしたダンプファイルEXPORT_SCHEMA_ADMIN.DMPをオブジェクトストレージ上に配置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/9489c073-4258-439d-ab48-ccfed5755c5a.png)

データ・ポンプのインポートをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/e2ee1ae5-272d-4c1b-82b5-89e37dd88670.png)

表示された画面で以下を入力し、次をクリックします。
+ バケットのソース　: バケット・リスト
+ 資格証明名 : OCI$RESOURCE_PRINCIPAL(リソースプリンシパル)、
+ コンパートメント名、バケット名 : EXPORT_SCHEMA_ADMIN.DMPをアップロードしたコンパートメント名、バケット名
+ パターンのインポート : バケット名まで入力するとバケットに存在するダンプファイルが表示されます。対象のファイルであるEXPORT_SCHEMA_ADMIN.DMPを選択すると自動入力されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/19a292e8-24fc-4e06-bd53-a0e6b9341e3e.png)

:::note warn 
2025/3現在、確認したところデータ・ポンプのクレデンシャルでクレデンシャルを指定すると次のエラーが発生し先に進めませんでした。

「コンパートメントをロードできません　資格証明"CRED_ADMIN"は無効です。別のものを選択してください。」
:::


次に表示された画面では以下を設定し、次をクリックします。

+ インポート名：任意（IMPORT_TAB_JOB）
+ インポート・タイプ：表　（フル、表、スキーマ、表領域から選択）
+ 内容：データのみ　（データとDDL、データのみ、DDLのみから選択）
+ クラウド・ディレクトリ：DATA_PUMP_DIR (ダンプファイルをアップロードするディレクトリを指定）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/231f0d48-a3b7-4e9e-865a-5e16873b724e.png)

ファイルをDATA_DUMP_DIRにコピー中と表示された後、ファイルに含まれている表の選択画面が表示されます。今回はEMPを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/799a04b4-8a95-4fc3-b23a-82df4089435a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/a18cebaa-04aa-4abc-bd85-3b03c0b450fc.png)

マッピングはないので、何もしないで次をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/4650ef97-73db-4cec-acf6-bb6532107b21.png)

オプションでは、表が存在する場合の表の処理で切り捨てを選択し、他はそのままにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/ed2a61c4-f3d0-4b57-9664-d7686e57f504.png)

サマリーが表示されます。コードの表示でコードの確認ができます。そのままインポートをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/69ddee99-b256-459e-9f4f-9e21016597d8.png)


ジョブが実行中になり、リフレッシュをすると完了となりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/4f587d9d-c196-4eb1-aebd-00e1d34f17db.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/9d62459c-1adc-40ec-8fa6-03b0085dd83f.png)


上のほうのリンクがログになるようです。英語でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/7d27877a-90ea-42e4-9659-e51baf5d28d7.png)

サマリーで表示されるコードはこちらです。このコードを使ってSQLで実行することもできます。

```sql
DECLARE
    L_JOB_STATE VARCHAR2(1000);
    L_JOB_HANDLE number;
    L_HAS_FAILED VARCHAR2(100):= 'ERROR';
    L_SHOULD_TRY_TO_GET_STATUS number := 0;
    L_TABLE_EXISTS NUMBER;
BEGIN
    L_JOB_HANDLE := dbms_datapump.open( operation => 'IMPORT', job_mode => 'TABLE', job_name => 'IMPORT_TAB_JOB_06_27_41', version => 'COMPATIBLE' );
    L_SHOULD_TRY_TO_GET_STATUS := 1;
    dbms_datapump.set_parallel( handle => L_JOB_HANDLE, degree => 1); 
    dbms_datapump.add_file( handle => L_JOB_HANDLE, filename => 'IMPORT_06_27_41.LOG', directory => 'DATA_PUMP_DIR', filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE );
    dbms_datapump.set_parameter( handle => L_JOB_HANDLE, name => 'KEEP_MASTER', value => 1 );
    dbms_datapump.add_file( handle => L_JOB_HANDLE, filename => 'EXPORT_SCHEMA_ADMIN.DMP', directory => 'DATA_PUMP_DIR', filetype => 1 );
    dbms_datapump.set_parameter( handle => L_JOB_HANDLE, name => 'INCLUDE_METADATA', value => 0 );
    dbms_datapump.set_parameter( handle => L_JOB_HANDLE, name => 'DATA_ACCESS_METHOD', value => 'AUTOMATIC' );
    dbms_datapump.set_parameter( handle => L_JOB_HANDLE, name => 'TABLE_EXISTS_ACTION', value => 'TRUNCATE' );
    dbms_datapump.set_parameter( handle => L_JOB_HANDLE, name => 'SKIP_UNUSABLE_INDEXES', value => 0 );
    dbms_datapump.start_job( handle => L_JOB_HANDLE, skip_current => 0, abort_step => 0 ); 
    dbms_datapump.wait_for_job( handle => L_JOB_HANDLE, job_state => L_JOB_STATE );
    dbms_datapump.detach( handle => L_JOB_HANDLE ); 
    L_HAS_FAILED := 'NO_ERROR';
EXCEPTION
    WHEN OTHERS THEN
        IF ( ( L_HAS_FAILED = 'ERROR' ) AND ( L_SHOULD_TRY_TO_GET_STATUS = 1 ) ) THEN 
            DBMS_DATAPUMP.DETACH( L_JOB_HANDLE );
        END IF;

        EXECUTE IMMEDIATE
            'SELECT COUNT(*) FROM DBA_TABLES WHERE TABLE_NAME='|| 
            DBMS_ASSERT.ENQUOTE_LITERAL ( 'IMPORT_TAB_JOB_06_27_41' )
            INTO L_TABLE_EXISTS;

        IF L_TABLE_EXISTS <> 0 THEN
            EXECUTE IMMEDIATE 
                'DROP TABLE' || DBMS_ASSERT.ENQUOTE_NAME ( 'IMPORT_TAB_JOB_06_27_41', FALSE );
        END IF;
END;

```

# 4.DBMS_DATAPUMPでObject Storageにエクスポートする
[23aiのドキュメント](https://docs.oracle.com/cd/F82042_01/sutil/using-oracle-data-pump-api.html#GUID-2CE28CE2-4B92-4473-8A00-71E23CFEEE3C)ではDBMS_DATAPUMPパッケージでObject Storageに出力できる記載があります。
先ほどのスクリプトを表指定にしてObject Storageに出力するようと編集してみました。

```sql
SET scan off
SET serveroutput ON
SET escape off
 
DECLARE
    h1 NUMBER;
    s VARCHAR2(1000):=NULL;
    errorvarchar VARCHAR2(100):= 'ERROR';
    tryGetStatus NUMBER := 0;
    success_with_info EXCEPTION;
    PRAGMA EXCEPTION_INIT(success_with_info, -31627);
BEGIN
-- 表モードを指定
    h1 := dbms_datapump.OPEN (operation => 'EXPORT', job_mode => 'TABLE', job_name => 'EXPORT_TAB_JOB', version => 'COMPATIBLE'); 
    tryGetStatus := 1;
--    dbms_datapump.set_parameter(handle => h1, name => 'COMPRESSION', VALUE => 'ALL'); 
--    dbms_datapump.set_parallel(handle => h1, degree => 1); 
    dbms_datapump.add_file(handle => h1, filename => 'EXPORT_TABLE_ADMIN.LOG', directory => 'DATA_PUMP_DIR', filetype => 3); 
　　dbms_datapump.set_parameter(handle => h1, name => 'KEEP_MASTER', VALUE => 1); 
-- EMP表を選択
    dbms_datapump.metadata_filter(handle => h1, name => 'NAME_EXPR', VALUE => 'IN(''EMP'')'); 
-- file_nameにObject Storage上のファイル名、directoryにクレデンシャル名、file_typeにDBMS_DATAPUMP.KU$_FILE_TYPE_URIDUMP_FILEを指定する
    dbms_datapump.add_file(handle => h1, filename => 'https://objectstorage.ap-tokyo-1.oraclecloud.com/n/<コンパートメント名>/b/<バケット名>/o/admintableexp%U.dmp', directory => 'CRED_ADMIN', filesize => '500M',  filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_URIDUMP_FILE); 
    dbms_datapump.set_parameter(handle => h1, name => 'INCLUDE_METADATA', VALUE => 1); 
    dbms_datapump.set_parameter(handle => h1, name => 'DATA_ACCESS_METHOD', VALUE => 'AUTOMATIC'); 
    dbms_datapump.set_parameter(handle => h1, name => 'ESTIMATE', VALUE => 'BLOCKS'); 
    dbms_datapump.start_job(handle => h1, skip_current => 0, abort_step => 0); 
    dbms_datapump.detach(handle => h1); 
    errorvarchar := 'NO_ERROR'; 
EXCEPTION
    WHEN OTHERS THEN
    BEGIN 
        IF ((errorvarchar = 'ERROR')AND(tryGetStatus=1)) THEN 
            DBMS_DATAPUMP.DETACH(h1);
        END IF;
    EXCEPTION 
    WHEN OTHERS THEN 
        NULL;
    END;
    RAISE;
END;
/
```

データ・ポンプで確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/d701a85c-c881-44ee-87c7-56aa49465365.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/fbd36e01-936d-4ddd-8d0c-2ef204390fb9.png)

完了したジョブからログは確認できますがダンプファイルのダウンロードはできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/75ddee24-fe1b-45c5-bb3c-7fcd050a5ced.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/2756f6ae-64f9-45cf-9c90-8810ce04a1fd.png)

対象のバケットを見てみると、ダンプファイルが出力されていました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134317/f3c30d16-a338-4cdd-a43d-5768d7c0910b.png)

次に、データ・ポンプでのインポートができるかも試してみたかったのですが、[ドキュメント](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/load-data-data-pump.html#GUID-3456B328-8C79-4BEE-A48C-881EBF5A1EC7)に以下のような記載があり、オブジェクトストレージに直接エクスポートした場合は、エクスポートで使用した同じクレデンシャルが必要です。

> If you use Oracle Data Pump expdp to export directly to Object Store then you must use the same credential that was used to export when you import with impdp. 

また[こちら](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/export-data-object-store-dp-new.html)の"Notes for Oracle Data Pump parameters:"に以下の記載があります。つまり、エクスポートではリソース・プリンシパルを利用することができないため、OCIユーザーのクレデンシャルを利用する必要があります。

> The credential parameter cannot be an OCI resource principal, Azure service principal, Amazon Resource Name (ARN), or a Google service account. See Accessing Cloud Resources by Configuring Policies and Roles for more information on resource principal based authentication.

しかし、データ・ポンプのインポートでは先のNoteにあるとおり、OCIユーザーのクレデンシャルを指定すると、エラーになってしまうため、できませんでした。

# おわりに
DBMS_DATAPUMPパッケージを使用したエクスポートとDatabase Actionsのデータ・ポンプの機能を試してみました。エクスポートもできるように今後のデータ・ポンプの機能強化に期待したいと思います。