データベース間でファイルの転送を行う DBMS_FILE_TRANSTER パッケージを試す

# データベース・サーバー間のファイル転送

データベース・サーバー間でファイルを転送したい場合が時々あります。Data Pump のダンプ・ファイルのコピーを行う場合などです。
scp コマンド等を使っても良いのですが、Oracle Database 10g 以降であれば、DBMS_FILE_TRANSFER パッケージを使うことで PL/SQL プログラム内からファイルの転送を行うことができます。
この方法を使うことで、オペレーティング・システムに対するファイル・アクセスが制限されているパブリック・クラウド内のマネージド・データベース間（Amazon RDSなど）でも、ファイルの転送を行うことができます。

DBMS_FILE_TRANSFER パッケージを使う場合、以下の条件でファイル転送を行うことができます。

- ファイルのコピー元、コピー先のディレクトリには DIRECTORY オブジェクトを使う。
- コピー先とコピー元は DATABASE LINK オブジェクトによる認証を行う。
- コピー元ユーザーは、コピー元 DIRECTORY に対する READ 権限、コピー先ユーザー（DATABASE LINK接続ユーザー）は、コピー先 DIRECTORY に対する WRITE 権限が必要。
- リモート・データベースに対するファイルの作成、リモート・データベースからのファイルのコピー、ローカル・データベース内のコピーができる。
- ファイル名の大文字／小文字は変換されない

ただし、ファイルであれば何でもコピーできるわけではなく、以下の制約があります。

- ファイルのサイズは 512 バイトの倍数であること
- ファイルのサイズの上限は 2 TB 以下

# DBMS_FILE_TRANSFER パッケージ
 DBMS_FILE_TRANSFER パッケージには以下のプロシージャが定義されています。
 
- COPY_FILE
 	ローカル・データベース内のファイル・コピー
 
- GET_FILE
 	リモート・データベース上のファイルを、ローカル・データベースにコピーする
 
- PUT_FILE
	ローカル・データベース上のファイルをリモート・データベースにコピーする

# 準備
 ここでは PUT_FILE プロシージャを使って、ローカル・データベース（O12R2A）に接続して、ローカル・データベースから、リモート・データベース（O12R2B）に対してファイルを転送する処理を行います。
 まず転送データを作成します。下記の例では Data Pump ユーティリティのダンプ・ファイル（scott.dmp）を作成しています。
 DIRECTORYオブジェクトは、標準の DATA_PUMP_DIR を使います。

```
$ expdp userid=SYSTEM/password SCHEMAS=scott DIRECTORY=DATA_PUMP_DIR DUMPFILE=scott.dmp

Export: Release 12.2.0.1.0 - Production on 火 2月 5 12:37:18 2019

Copyright (c) 1982, 2017, Oracle and/or its affiliates.  All rights reserved.

接続先: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
"SYSTEM"."SYS_EXPORT_SCHEMA_01"を起動しています: userid=SYSTEM/******** SCHEMAS=scott DIRECTORY=DATA_PUMP_DIR DUMPFILE=scott.dmp
オブジェクト型SCHEMA_EXPORT/TABLE/TABLE_DATAの処理中です
オブジェクト型SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICSの処理中です
オブジェクト型SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICSの処理中です
オブジェクト型SCHEMA_EXPORT/STATISTICS/MARKERの処理中です
オブジェクト型SCHEMA_EXPORT/USERの処理中です
オブジェクト型SCHEMA_EXPORT/SYSTEM_GRANTの処理中です
オブジェクト型SCHEMA_EXPORT/ROLE_GRANTの処理中です
オブジェクト型SCHEMA_EXPORT/DEFAULT_ROLEの処理中です
オブジェクト型SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMAの処理中です
オブジェクト型SCHEMA_EXPORT/SEQUENCE/SEQUENCEの処理中です
オブジェクト型SCHEMA_EXPORT/TABLE/TABLEの処理中です
オブジェクト型SCHEMA_EXPORT/PROCEDURE/PROCEDUREの処理中です
オブジェクト型SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDUREの処理中です
オブジェクト型SCHEMA_EXPORT/TABLE/INDEX/INDEXの処理中です
オブジェクト型SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINTの処理中です
. . "SCOTT"."EMPLOYEES"                         114.2 MB 8000000行がエクスポートされました
マスター表"SYSTEM"."SYS_EXPORT_SCHEMA_01"は正常にロード/アンロードされました
******************************************************************************
SYSTEM.SYS_EXPORT_SCHEMA_01に設定されたダンプ・ファイルは次のとおりです:
  /u01/app/oracle/admin/O12R2A/dpdump/scott.dmp
ジョブ"SYSTEM"."SYS_EXPORT_SCHEMA_01"が火 2月 5 12:38:25 2019 elapsed 0 00:00:56で正常に完了しました

```

ファイルが作成されたことを確認します。

```

$ sqlplus / as sysdba

Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
に接続されました。

SQL> SELECT DIRECTORY_PATH FROM DBA_DIRECTORIES WHERE DIRECTORY_NAME='DATA_PUMP_DIR';

DIRECTORY_PATH
--------------------------------------------------------------------------------
/u01/app/oracle/admin/O12R2A/dpdump/

SQL> 
SQL> !ls -l /u01/app/oracle/admin/O12R2A/dpdump/
合計 117432
-rw-r----- 1 oracle oinstall       118 12月 21 10:53 dp.log
-rw-r--r-- 1 oracle asmadmin      2227  2月  5 12:38 export.log
-rw-r----- 1 oracle asmadmin 120242176  2月  5 12:38 scott.dmp

```

次にデータ転送用にリモート・データベースに接続する DATABASE LINK オブジェクトを作成します。

```
$ sqlplus / as sysdba

Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
に接続されました。

SQL> CREATE PUBLIC DATABASE LINK REMOTE_DL1 CONNECT TO SYSTEM IDENTIFIED BY password USING 'O12R2B';

データベース・リンクが作成されました。

```

転送先データベースでも DIRECTORY オブジェクトが存在することを確認します。

```
SQL> SELECT DIRECTORY_PATH FROM DBA_DIRECTORIES WHERE DIRECTORY_NAME='DATA_PUMP_DIR';

DIRECTORY_PATH
--------------------------------------------------------------------------------
/u01/app/oracle/admin/O12R2B/dpdump/

```

# ファイル転送の実行

PUT_FILE プロシージャを実行します。以下のパラメーターを指定します。

|パラメーター名|データ型 | 説明 |
|:---|:---|:---|
|SOURCE_DIRECTORY_OBJECT|VARCHAR2|コピー元 DIRECTORY オブジェクト名|
|SOURCE_FILE_NAME|VARCHAR2|コピー元ファイル名|
|DESTINATION_DIRECTORY_OBJECT|VARCHAR2|コピー先DIRECTORY オブジェクト名|
|DESTINATION_FILE_NAME|VARCHAR2|コピー先ファイル名|
|DESTINATION_DATABASE|VARCHAR2|コピー先データベースに接続する DATABASE LINK 名|

```

SQL> BEGIN
  2      DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp', 'DATA_PUMP_DIR', 'scott_dst.dmp', 'REMOTE_DL1');
  3  END;
  4  /

PL/SQLプロシージャが正常に完了しました。

SQL>

```

転送先データベースで、ファイルが存在するか確認します。

```

SQL> SELECT DIRECTORY_PATH FROM DBA_DIRECTORIES WHERE DIRECTORY_NAME='DATA_PUMP_DIR';

DIRECTORY_PATH
--------------------------------------------------------------------------------
/u01/app/oracle/admin/O12R2B/dpdump/

SQL> !ls -l /u01/app/oracle/admin/O12R2B/dpdump/
合計 117428
-rw-r----- 1 oracle asmadmin       118  2月  5 11:55 dp.log
-rw-r----- 1 oracle asmadmin 120242176  2月  5 12:41 scott_dst.dmp

```

# エラー発生
　PUT_FILEプロシージャを実行する際に発生する可能性があるエラーをいくつか再現します。

## TNS識別子が存在しない
tnsnames.ora ファイルに記述された接続子名を間違えた場合のエラー。

```
SQL> BEGIN
  2  DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp', 'DATA_PUMP_DIR', 'scott_dst.dmp', 'REMOTE_DL2');
  3  END;
  4  /
BEGIN
*
行1でエラーが発生しました。:
ORA-02019: 指定されたリモート・データベースは存在しません。 ORA-06512:
"SYS.DBMS_FILE_TRANSFER", 行76
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行184
ORA-06512: 行2
```

## 転送元 DIRECTORY が存在しない場合

source_directory_object パラメーターに指定した DIRECTORY オブジェクトが存在しない場合のエラー

```
SQL> BEGIN
  2  DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR1', 'scott.dmp', 'DATA_PUMP_DIR', 'scott_dst.dmp', 'REMOTE_DL1');
  3  END;
  4  /
BEGIN
*
行1でエラーが発生しました。:
ORA-06564: オブジェクトDATA_PUMP_DIR1は存在しません。 ORA-06512:
"SYS.DBMS_FILE_TRANSFER", 行76
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行184
ORA-06512: 行2

```

## 転送先 DIRECTORY が存在しない場合

destination_directory_object パラメーターに指定した DIRECTORY オブジェクトが存在しない場合のエラー

```
SQL> BEGIN
  2  DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp', 'DATA_PUMP_DIR2', 'scott_dst.dmp', 'REMOTE_DL1');
  3  END;
  4  /
BEGIN
*
行1でエラーが発生しました。:
ORA-06564: オブジェクトDATA_PUMP_DIR2は存在しません。 ORA-02063:
先行のエラー・メッセージを参照してくださいline(REMOTE_DL1)。 ORA-06512:
"SYS.DBMS_FILE_TRANSFER", 行76
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行184
ORA-06512: 行2

```

## 転送元ファイルが存在しない場合

source_file_name パラメーターに指定されたファイルが存在しない場合のエラー。

```
SQL> BEGIN
  2  DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp2', 'DATA_PUMP_DIR', 'scott_dst.dmp', 'REMOTE_DL1');
  3  END;
  4  /
BEGIN
*
行1でエラーが発生しました。:
ORA-19505:
ファイル"/u01/app/oracle/admin/O12R2A/dpdump/scott.dmp2"の識別に失敗しました。 ORA-27037:
ファイル・ステータスを取得できません。 Linux-x86_64 Error:
2: No such file or directory
Additional information: 7
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行76
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行184
ORA-06512: 行2

```

## 書込み先にファイルが存在する
  転送先ディレクトリに既に同名のファイルが存在する場合のエラー

```
SQL> BEGIN
  2  DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp', 'DATA_PUMP_DIR', 'scott_dst.dmp', 'REMOTE_DL1');
  3  END;
  4  /
BEGIN
*
行1でエラーが発生しました。:
ORA-19504:
ファイル"/u01/app/oracle/admin/O12R2B/dpdump/scott_dst.dmp"の作成に失敗しました
。
ORA-27038: 作成したファイルはすでに存在します Additional
information: 1
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(REMOTE_DL1)。 ORA-06512:
"SYS.DBMS_FILE_TRANSFER", 行76
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行184
ORA-06512: 行2

```

## 転送先データベース・インスタンスが停止している
転送先データベース・インスタンスまたはリスナー等が停止している場合のエラー。

```
SQL> BEGIN
  2  DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp', 'DATA_PUMP_DIR', 'scott_dst.dmp', 'REMOTE_DL1');
  3  END;
  4  /
BEGIN
*
行1でエラーが発生しました。:
ORA-03150: データベース・リンクの通信チャネルでend-of-fileが検出されました ORA-02063:
先行のエラー・メッセージを参照してくださいline(REMOTE_DL1)。 ORA-06512:
"SYS.DBMS_FILE_TRANSFER", 行76
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行184
ORA-06512: 行2

SQL> BEGIN
  2  DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp', 'DATA_PUMP_DIR', 'scott_dst.dmp', 'REMOTE_DL1');
  3* END;
SQL> /
BEGIN
*
行1でエラーが発生しました。:
ORA-12514: TNS:
リスナーは接続記述子でリクエストされたサービスを現在認識していません ORA-06512:
"SYS.DBMS_FILE_TRANSFER", 行76
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行184
ORA-06512: 行2

SQL> BEGIN
  2  DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp', 'DATA_PUMP_DIR', 'scott_dst.dmp', 'REMOTE_DL1');
  3* END;
SQL> /
BEGIN
*
行1でエラーが発生しました。:
ORA-12541: TNS: リスナーがありません ORA-06512:
"SYS.DBMS_FILE_TRANSFER", 行76
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行184
ORA-06512: 行2

```