ora2pgを使用してOracleからPostgreSQLへ移行する

# はじめに

ora2pgはOracle(とMySQL）からPostgreSQLへの移行を支援するためのツールです。
ora2pgにより以下のことを自動で行えます。

・スキーマ定義のDDL生成
　Oracleデータベースに接続し、オブジェクト定義を読み出し、PostgreSQL用のDDLを生成します。
・PostgreSQLへのマイグレーションの評価レポートの生成
　全てのデータベースオブジェクト、ストアドプロシージャ等を検査して、ora2pgによって自動で変換できるかなどのレポートを生成します。
・SQLのコンバート
　SQLファイルを読み込み、PostgreSQL用のSQLに変換します。
・データ移行用のDML生成
　Oracleデータベースに接続し、移行用のDMLを生成します。

今回はora2pgのスキーマ定義のDDL生成と評価レポートの出力を実行してみます。
SQLのコンバートはまた今度。


ora2pg
http://ora2pg.darold.net/

# 環境

使用する環境は以下のとおりです。

- CentOS 7.4
- ora2pg v20.0
- Oracle12cR2

Oracleには事前に[Oracle Database Sample Schemas](https://github.com/oracle/db-sample-schemas/releases/tag/v12.2.0.1)でスキーマを作成しています。


# インストール

ora2pgのインストールは以下のサイトを参考に実施しました。
http://ora2pg.darold.net/documentation.html#INSTALLATION

まず、Oracleへの接続のため、[Instant Client Package](https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html)をインストールします。

インストールするのは以下の4つ。

- oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm
- oracle-instantclient12.2-devel-12.2.0.1.0-1.x86_64.rpm 
- oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm
- oracle-instantclient12.2-jdbc-12.2.0.1.0-1.x86_64.rpm

```
rpm -ivh oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm
rpm -ivh oracle-instantclient12.2-devel-12.2.0.1.0-1.x86_64.rpm 
rpm -ivh oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm
rpm -ivh oracle-instantclient12.2-jdbc-12.2.0.1.0-1.x86_64.rpm
```

インストール後、LD_LIBRARY_PATHとORACLE_HOMEを設定します。

```
# vi .bash_profile
export LD_LIBRARY_PATH=/usr/lib/oracle/12.2/client64/lib
export ORACLE_HOME=/usr/lib/oracle/12.2/client64/lib
# source .bash_profile
```

次にora2pgが利用するPerlのモジュールのインストールのため、perl-CPANをインストールします。
また、ora2pgはYAMLを使用するためlibyaml-develもインストールします。

```
# yum -y install perl-CPAN
# yum -y install libyaml-devel
```

CPANを初めて実行する場合は色々と設定が必要なようです。
以下を実行すると色々聞かれますが、基本全部Enterで問題ないです。

```
# perl -MCPAN -e shell
```

Oracleへの接続のためDBIとDBD::Oracleをインストールします。

```
# perl -MCPAN -e 'install DBI'
# perl -MCPAN -e 'install DBD::Oracle'
```

公式サイトからora2pg-20.0.tar.bz2をダウンロードし、コンパイル・インストールします。
これでora2pgコマンドが/usr/local/bin以下にインストールされます。

```
# tar xjf ora2pg-20.0.tar.bz2 
# cd ora2pg-20.0
# perl Makefile.PL
# make && make install
```


# ora2pgの実行

ora2pgを実行する前に設定ファイルやエクスポート用のディレクトリ等で構成されるプロジェクトテンプレートを作成します。
プロジェクトテンプレートを作成するためには、--project_baseと--init_projectのオプションを使用して、以下のコマンドを実行します。

```
# mkdir ~/migration
# ora2pg --project_base ~/migration --init_project test_project
Creating project test_project.
/root/migration/test_project/
        schema/
                dblinks/
                directories/
                functions/
                grants/
                mviews/
                packages/
                partitions/
                procedures/
                sequences/
                synonyms/
                tables/
                tablespaces/
                triggers/
                types/
                views/
        sources/
                functions/
                mviews/
                packages/
                partitions/
                procedures/
                triggers/
                types/
                views/
        data/
        config/
        reports/

Generating generic configuration file
Creating script export_schema.sh to automate all exports.
Creating script import_all.sh to automate all imports.
```

プロジェクトテンプレートでora2pgの設定ファイルが作成されます。
作成されたora2pgの設定ファイルは以下になります。

```
~/migration/test_project/config/ora2pg.conf
```

この設定ファイルを環境に合わせて修正します。
今回は以下の1, 4行目を修正しています。

```
ORACLE_DSN      dbi:Oracle:host=192.168.10.232;sid=testdb;port=1521
ORACLE_USER     system # 必要に応じて
ORACLE_PWD      manager # 必要に応じて
SCHEMA  hr
```

設定ファイルの修正が完了したら、以下のコマンドを実行してOracleへ接続できることを確認します。

```
# cd ~/migration/test_project
# ora2pg -t SHOW_VERSION -c config/ora2pg.conf
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0
```

Oracleへの接続が確認できたらいよいよ実行です。プロジェクトテンプレートでは一括でコンバートするスクリプト（export_schema.sh）が自動生成されていますので、こちらを実行します。

```
# ./export_schema.sh
```

実行が終わった後でtreeコマンドを実行すると、以下のように各種ファイルが生成されたことが分かります。

```
[root@postgresserver1 test_project]# tree
.
├── config
│   └── ora2pg.conf
├── data
├── export_schema.sh
├── import_all.sh
├── reports
│   ├── columns.txt
│   ├── report.html
│   └── tables.txt
├── schema
│   ├── dblinks
│   ├── directories
│   ├── functions
│   ├── grants
│   ├── mviews
│   ├── packages
│   ├── partitions
│   │   └── partition.sql
│   ├── procedures
│   │   ├── ADD_JOB_HISTORY_procedure.sql
│   │   ├── procedure.sql
│   │   └── SECURE_DML_procedure.sql
│   ├── sequences
│   │   └── sequence.sql
│   ├── synonyms
│   ├── tables
│   │   ├── CONSTRAINTS_table.sql
│   │   ├── FKEYS_table.sql
│   │   ├── INDEXES_table.sql
│   │   └── table.sql
│   ├── tablespaces
│   ├── triggers
│   │   ├── trigger.sql
│   │   └── UPDATE_JOB_HISTORY_trigger.sql
│   ├── types
│   └── views
│       ├── EMP_DETAILS_VIEW_view.sql
│       └── view.sql
└── sources
    ├── functions
    ├── mviews
    ├── packages
    ├── partitions
    │   └── partition.sql
    ├── procedures
    │   ├── ADD_JOB_HISTORY_procedure.sql
    │   ├── procedure.sql
    │   └── SECURE_DML_procedure.sql
    ├── triggers
    │   ├── trigger.sql
    │   └── UPDATE_JOB_HISTORY_trigger.sql
    ├── types
    └── views
        ├── EMP_DETAILS_VIEW_view.sql
        └── view.sql

28 directories, 27 files
```


評価レポートの出力結果（report.html）は以下のようになりました。
Estimated costでora2pgを実行後に手動で修正が必要なコストが分かります。
今回は26.6となっています。1unitが5分なので2時間ぐらいのようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/e324622f-c779-fbb1-ef68-a26905acb12d.png)

生成されたファイルのうち、テーブル定義のtable.sqlを確認してみます。
employeesテーブルだけ見てみると以下のように変換されています。
上がOracle（変換前）、下がPostgreSQL（変換後）です。
NUMBERがinteger、smallint等に変換されていることが分かります。

```
# Oracle（変換前）
CREATE TABLE employees
    ( employee_id    NUMBER(6)
    , first_name     VARCHAR2(20)
    , last_name      VARCHAR2(25)
	 CONSTRAINT     emp_last_name_nn  NOT NULL
    , email          VARCHAR2(25)
	CONSTRAINT     emp_email_nn  NOT NULL
    , phone_number   VARCHAR2(20)
    , hire_date      DATE
	CONSTRAINT     emp_hire_date_nn  NOT NULL
    , job_id         VARCHAR2(10)
	CONSTRAINT     emp_job_nn  NOT NULL
    , salary         NUMBER(8,2)
    , commission_pct NUMBER(2,2)
    , manager_id     NUMBER(6)
    , department_id  NUMBER(4)
    , CONSTRAINT     emp_salary_min
                     CHECK (salary > 0) 
    , CONSTRAINT     emp_email_uk
                     UNIQUE (email)
    ) ;

# PostgreSQL（変換後）
CREATE TABLE employees (
        employee_id integer NOT NULL,
        first_name varchar(20),
        last_name varchar(25) NOT NULL,
        email varchar(25) NOT NULL,
        phone_number varchar(20),
        hire_date timestamp NOT NULL,
        job_id varchar(10) NOT NULL,
        salary double precision,
        commission_pct real,
        manager_id integer,
        department_id smallint
) ;
```

先ほどは一括で変換しましたが、個別に実行する場合は以下のようになります。

```
テーブル定義のみ出力する。-t(Export type)の値を変更することで他のオブジェクトも変換できます。
# ora2pg -c config/ora2pg.conf -t TABLE

評価レポートを出力する。
# ora2pg -c config/ora2pg.conf -t SHOW_REPORT --estimate_cost --dump_as_html > report.html

SQLだけを変換する。
# ora2pg -c config/ora2pg.conf -i input.sql -o output.sql -t QUERY
```

[公式サイト](http://ora2pg.darold.net/documentation.html#Oracle-schema-to-export)を参照すると、以下のExport typeが選択できるようです。

```
        - TABLE: Extract all tables with indexes, primary keys, unique keys,
          foreign keys and check constraints.
        - VIEW: Extract only views.
        - GRANT: Extract roles converted to Pg groups, users and grants on all
          objects.
        - SEQUENCE: Extract all sequence and their last position.
        - TABLESPACE: Extract storage spaces for tables and indexes (Pg >= v8).
        - TRIGGER: Extract triggers defined following actions.
        - FUNCTION: Extract functions.
        - PROCEDURE: Extract procedures.
        - PACKAGE: Extract packages and package bodies.
        - INSERT: Extract data as INSERT statement.
        - COPY: Extract data as COPY statement.
        - PARTITION: Extract range and list Oracle partitions with subpartitions.
        - TYPE: Extract user defined Oracle type.
        - FDW: Export Oracle tables as foreign table for oracle_fdw.
        - MVIEW: Export materialized view.
        - QUERY: Try to automatically convert Oracle SQL queries.
        - KETTLE: Generate XML ktr template files to be used by Kettle.
        - DBLINK: Generate oracle foreign data wrapper server to use as dblink.
        - SYNONYM: Export Oracle's synonyms as views on other schema's objects.
        - DIRECTORY: Export Oracle's directories as external_file extension objects.
        - LOAD: Dispatch a list of queries over multiple PostgreSQl connections.
        - TEST: perform a diff between Oracle and PostgreSQL database.
        - TEST_VIEW: perform a count on both side of rows returned by views
```

SQLの変換については以下の投稿でいくつかのSQLの変換を試しています。

- [ora2pgを使用してOracleのSQLをPostgreSQLへ変換する](https://qiita.com/mkyz08/items/8629cfb221a864469a55)


# 参考

- [ora2pg（公式サイト）](http://ora2pg.darold.net/index.html)
- [このora2pgがすごい！Oracleのストアドプロシージャ2種をPostgreSQLに移行してみた！](https://www.ntt-tx.co.jp/column/postgresql_blog/20171027/)
- [データベースマイグレーション ～OracleからPostgreSQLへ～　－第２回ー](https://future-architect.github.io/articles/20180809/)