expdpで作成したダンプファイルのスキーマ名を確認したい ( impdpのSQLFILEを使用 )

最近会社で聞かれて答えたことをまとめてみました。

> 客先から提供されたOracleダンプファイル(impdp/expdp)がある。エクスポート元のスキーマ名が分からない。知る方法はあるだろうか？

さて、ファイル提供元がスキーマを知らないのでスキーマを教えてもらえないという非常に特殊なシチュエーションです。

実は会社では、「公式パッケージ"DBMS_DATAPUMP"を使用し、Open時にOPERATION=>SQLFILE指定する」という方法を説明しました。そのころはimpdpだけで分かるということを知らなかったからです。ここではもっと簡単に確認できる、impdpを用いる方法を説明します。

以下、環境は11gを想定して説明しています。

# 概要

impdpは、公式ユーティリティexpdpによって出力(エクスポート)されたダンプファイルを、DBに投入(インポート)する公式ユーティリティです。しかし、impdpには、実際にはインポートせずに、インポート時に実行される予定のDDL群をファイルに出力するという機能を持っています。impdpのパラメータにSQLFILEを指定すると、この機能を使うことができます。ここではこの機能に特化して説明します。

この機能を含めてimpdpの詳細な説明は、[公式ドキュメント](https://docs.oracle.com/cd/E16338_01/server.112/b56303/dp_import.htm)に記載されています。

# 実験

実際に試してみることにしましょう。実験環境は、[Oracle Database 11g on docker](https://qiita.com/szly/items/9c38a3a02247e4d837c6#oracle-11g-xe)です。

## テスト用ダンプファイルの作成

まずは、テスト用のスキーマとテスト用のオブジェクトを作成します。

```
-- DROP USER TEST2 CASCADE;
CREATE USER TEST2 IDENTIFIED BY TEST2;
GRANT CONNECT TO TEST2;
GRANT DBA TO TEST2;
CREATE TABLE TEST2.TBL_TEST AS SELECT * FROM DUAL;
CREATE PROCEDURE TEST2.PRC_TEST IS BEGIN NULL; END;
/
```

これをexpdpしてみます。"docker exec -it oracle11g /bin/bash"の中で実行しています。

```
bash-4.2# expdp TEST2/TEST2@127.0.0.1:1521/XE DIRECTORY=DATA_PUMP_DIR DUMPFILE=sample.dat

Export: Release 11.2.0.2.0 - Production on Sat Jun 13 20:34:08 2020

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

Connected to: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
Starting "TEST2"."SYS_EXPORT_SCHEMA_01":  TEST2/********@127.0.0.1:1521/XE DIRECTORY=DATA_PUMP_DIR DUMPFILE=sample.dat
Estimate in progress using BLOCKS method...
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 64 KB
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/ROLE_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/COMMENT
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
. . exported "TEST2"."TBL_TEST"                          5.007 KB       1 rows
Master table "TEST2"."SYS_EXPORT_SCHEMA_01" successfully loaded/unloaded
******************************************************************************
Dump file set for TEST2.SYS_EXPORT_SCHEMA_01 is:
  /u01/app/oracle/admin/XE/dpdump/sample.dat
Job "TEST2"."SYS_EXPORT_SCHEMA_01" successfully completed at 20:34:28

bash-4.2#
```

ここでは、dockerコンテナの中だけで残りの実験を進めてみます。"docker cp"でdockerコンテナの外に持ち出して、別のDB環境で試しても構いません。

## SQLFILE機能の確認

以下のコマンドを使うことにします。

```
impdp TEST/TEST@127.0.0.1:1521/XE DUMPFILE=DATA_PUMP_DIR:sample.dat SQLFILE=DATA_PUMP_DIR:sample.sql
```

説明を3点しておきます。

* impdpの接続先"TEST"には、インポート対象の"TEST2"とは無関係なものを指定しています。
* パラメータ"SQLFILE"が指定されているため、DBへのデータ投入は行われません。
* パラメータ"SQLFILE"に"ディレクトリオブジェクト名:ファイル名"の表記を用いています。そのため、パラメータ"DIRECTORY"とは無関係に書き出し先を指定することができます。この機能はパラメータ"DUMPFILE"で使用できるものと同じです。

コマンド"impdp"実行前にユーザー"TEST2"を削除しておくと、「DBへのデータ投入は行われません」という部分の動きが分かりやすくなります。ここではそのあたりの説明や確認を省略しています。試す場合には、ユーザー"TEST2"を削除して、impdp実行後に作成されていないことを確認してみるとよいでしょう。

impdpを実行すると、以下のようになります。

```
bash-4.2# impdp TEST/TEST@127.0.0.1:1521/XE DUMPFILE=DATA_PUMP_DIR:sample.dat SQLFILE=DATA_PUMP_DIR:sample.sql

Import: Release 11.2.0.2.0 - Production on Sat Jun 13 20:51:36 2020

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

Connected to: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
Master table "TEST"."SYS_SQL_FILE_FULL_01" successfully loaded/unloaded
Starting "TEST"."SYS_SQL_FILE_FULL_01":  TEST/********@127.0.0.1:1521/XE DUMPFILE=DATA_PUMP_DIR:sample.dat SQLFILE=DATA_PUMP_DIR:sample.sql
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/ROLE_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Job "TEST"."SYS_SQL_FILE_FULL_01" successfully completed at 20:51:37

bash-4.2#
```

impdp実行後、SQLFILEで指定された場所にファイルが作成されます。作成される場所はどこでしょうか。前節で実施した、コマンドexpdpの出力結果の末尾を見ると分かります。該当箇所を抜粋します。

```
Dump file set for TEST2.SYS_EXPORT_SCHEMA_01 is:
  /u01/app/oracle/admin/XE/dpdump/sample.dat
```

expdp実行時に指定したディレクトリオブジェクト"DATA_PUMP_DIR"は、ディレクトリ"/u01/app/oracle/admin/XE/dpdump/"を指しているようです。SQLFILEで指定したディレクトリオブジェクトも同じです。そのため、同じディレクトリにファイルが作成されているはずです。確認してみましょう。

```
bash-4.2# ls -l /u01/app/oracle/admin/XE/dpdump/
total 192
-rw-r--r-- 1 oracle dba   1572 Jun 13 20:34 export.log
-rw-r--r-- 1 oracle dba    949 Jun 13 20:51 import.log
-rw-r----- 1 oracle dba 184320 Jun 13 20:34 sample.dat
-rw-r--r-- 1 oracle dba   2020 Jun 13 20:51 sample.sql
bash-4.2#
```

パラメータ"SQLFILE"で指定したファイル"sample.sql"が作成されていることが分かります。作成されたファイルを見てみることにします。

```
bash-4.2# cat /u01/app/oracle/admin/XE/dpdump/sample.sql
-- CONNECT TEST
ALTER SESSION SET EVENTS '10150 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '10904 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '25475 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '10407 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '10851 TRACE NAME CONTEXT FOREVER, LEVEL 1';
ALTER SESSION SET EVENTS '22830 TRACE NAME CONTEXT FOREVER, LEVEL 192 ';
-- new object type path: SCHEMA_EXPORT/USER
-- CONNECT SYSTEM
 CREATE USER "TEST2" IDENTIFIED BY VALUES 'S:C7580FEC4D5F508279B393FD7967A2D7C866B8FE45D15E45F74B2C3E1BB0;2E3197EF1322CB1D'
      TEMPORARY TABLESPACE "TEMP";
-- new object type path: SCHEMA_EXPORT/SYSTEM_GRANT
GRANT UNLIMITED TABLESPACE TO "TEST2";
-- new object type path: SCHEMA_EXPORT/ROLE_GRANT
 GRANT "CONNECT" TO "TEST2";
 GRANT "DBA" TO "TEST2";
-- new object type path: SCHEMA_EXPORT/DEFAULT_ROLE
 ALTER USER "TEST2" DEFAULT ROLE ALL;
-- new object type path: SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
-- CONNECT TEST2

BEGIN
sys.dbms_logrep_imp.instantiate_schema(schema_name=>SYS_CONTEXT('USERENV','CURRENT_SCHEMA'), export_db_name=>'XE', inst_scn=>'1638367');
COMMIT;
END;
/
-- new object type path: SCHEMA_EXPORT/TABLE/TABLE
-- CONNECT TEST
CREATE TABLE "TEST2"."TBL_TEST"
   (    "DUMMY" VARCHAR2(1 BYTE)
   ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "SYSTEM" ;
-- new object type path: SCHEMA_EXPORT/PROCEDURE/PROCEDURE
-- CONNECT TEST2
CREATE PROCEDURE       PRC_TEST IS BEGIN NULL; END;
/
-- new object type path: SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE

ALTER PROCEDURE "TEST2"."PRC_TEST"
  COMPILE
    PLSQL_OPTIMIZE_LEVEL=  2
    PLSQL_CODE_TYPE=  INTERPRETED
    PLSQL_DEBUG=  FALSE    PLSCOPE_SETTINGS=  'IDENTIFIERS:NONE'

 REUSE SETTINGS TIMESTAMP '2020-06-13 20:30:13'
/
```

DDLがファイルに書き込まれていることが分かります。

## もともとの疑問に対する確認結果

もともとの疑問は何だったでしょうか。ダンプファイルに含まれているスキーマ名は何だろうか、でした。"CREATE USER"付近を抜粋してみます。

```
    :
-- new object type path: SCHEMA_EXPORT/USER
-- CONNECT SYSTEM
 CREATE USER "TEST2" IDENTIFIED BY VALUES 'S:C7580FEC4D5F508279B393FD7967A2D7C866B8FE45D15E45F74B2C3E1BB0;2E3197EF1322CB1D'
      TEMPORARY TABLESPACE "TEMP";
    :
```

パスワードは一見分からない形になっています。しかし、これを見ればユーザー"TEST2"を作成していることが分かります。

後続するオブジェクト作成時のDDLも抜粋してみます。

```
    :
-- CONNECT TEST
CREATE TABLE "TEST2"."TBL_TEST"
    :
-- CONNECT TEST2
CREATE PROCEDURE       PRC_TEST IS BEGIN NULL; END;
    :
```

スキーマ"TEST2"の下にオブジェクトを作成していることがわかります。TABLE作成時はユーザー"TEST"で接続してスキーマ"TEST2"の下に作成、PROCEDURE作成時はユーザー"TEST2"で接続して自スキーマの下に作成というように、興味深い違いが見受けられます。しかし、ここでの主題とは異なるため、気にしないでおきます。

ともあれ、これらの情報をまとめるとエクスポート元のスキーマは"TEST2"であることが分かります。

複数ユーザーがまとめてexpdpされている場合は、"CREATE USER"も複数あるはずです。同様に確認できるでしょう。

# まとめ

impdpをパラメータ"SQLFILE"とともに使うことで、ダンプファイルに含まれているオブジェクトをDB投入する際のDDLがファイルに出力されます。

これによって、ダンプファイルに含まれるスキーマ名を確認することができます。また、TABLE、PROCEDURE/FUNCTION/PACKAGE、権限なども確認することができます。TABLEではSTORAGE句なども分かります。

会社ではパッケージ"DBMS_DATAPUMP"を使うという大げさなことをしてしまいました。この方法を知ったので、今後はもっと簡単に確認することができるでしょう。