Oracle Database 12c新機能 Data Pumpによる文字コード変換エラー機能を試す

# Data Pumpと文字コードの変換
Oracle Databaseは文字列型のエンコードをデータベース単位に決定します。
Oracle Database Clientはデータベースのエンコードとクライアントのエンコードを自動的に変換することでアプリケーションから文字コードの違いを隠蔽しています。
　Data PumpはOracle Databaseに付属するツールで、論理バックアップやデータの移行に使われています。ここではData Pumpを使って、日本語EUC（JA16EUC）を使ったデータベースからUTF-8（AL32UTF8）を使ったデータベースへ移行する際に文字コード変換エラーを検知する方法について検証します。

# JA16EUCと外字
Oracle Databaseの日本語EUC文字コードであるJA16EUCには、Shift_JISにMicrosoftやIBMが追加した外字に相当するエンコードが含まれません。Shift_JISでは0x8740、日本語EUCでは0xADA1に定義された「①」はJA16EUCには含まれません。Oracle Databaseに付属するLocale Builderを使うと、エンコードに含まれる文字のコードを確認することができます。
　JA16EUCには①等のコードは含まれませんが、Oracle Databaseはクライアントとサーバー間の文字コードが同一の場合、文字コードチェックを行わないため、本来では格納すべきではない文字も格納できる場合があります。

```
$ printenv NLS_LANG
Japanese_Japan.JA16EUC
$
$ sqlplus / as sysdba
SQL> SELECT value FROM V$NLS_PARAMETERS WHERE name='NLS_CHARACTERSET' ;
VALUE
----------------------------------------------------------------
JA16EUC

SQL> INSERT INTO SCOTT.DATA1 VALUES ('①') ;	-- 0xADA1を格納

1行が作成されました。

SQL> COMMIT ;

コミットが完了しました。

SQL> SELECT DUMP(c1, 16) FROM SCOTT.DATA1 ;

DUMP(C1,16)
--------------------------------------------------------------------------------
Typ=1 Len=2: ad,a1

```

# Data Pumpを使ったデータ移行
 expdpコマンドとimpdpコマンドを使ってデータベースのデータを移行します。

```
-- 移行元データベース（JA16EUCJP）
$ expdp SYSTEM/pass SCHEMAS=SCOTT DIRECTORY=dir1 DUMPFILE=expdat.dmp 

Export: Release 11.2.0.4.0 - Production on 日 11月 19 12:16:46 2017

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

...

-- 移行先データベース（AL32UTF8）
$ impdp SYSTEM/pass SCHEMAS=SCOTT DIRECTORY=dir1 DUMPFILE=expdat.dmp

Import: Release 12.2.0.1.0 - Production on Mon Nov 20 12:30:32 2017

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

Connected to: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
Master table "SYSTEM"."SYS_IMPORT_SCHEMA_01" successfully loaded/unloaded
import done in AL32UTF8 character set and AL16UTF16 NCHAR character set
export done in JA16EUC character set and AL16UTF16 NCHAR character set
Warning: possible data loss in character set conversions

...

```

 0xADA1の文字コードは変換できなかったはずですが、エラーは発生していません。移行先データを確認するとREPLACEMENT CHARACTER (0xEFBFBD)に変換されていることがわかります。

```
-- 移行先データベース（AL32UTF8）
SQL> SELECT c1, DUMP(c1, 16) DUMP FROM SCOTT.DATA1 ;

C1    DUMP
----- ------------------------------
?     Typ=1 Len=3: ef,bf,bd

```

# データ移行時に変換エラーを拒否

impdpコマンドに data_options=REJECT_ROWS_WITH_REPL_CHARを指定すると、文字コード変換エラーが発生したレコードは拒否され、変換エラーの情報がログに出力されるようになります。

```
-- 移行先データベース（AL32UTF8）
$ impdp SYSTEM/pass SCHEMAS=SCOTT DIRECTORY=dir1 DUMPFILE=expdat.dmp data_options=REJECT_ROWS_WITH_REPL_CHAR

Import: Release 12.2.0.1.0 - Production on Mon Nov 20 12:26:14 2017

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

Connected to: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
Master table "SYSTEM"."SYS_IMPORT_SCHEMA_01" successfully loaded/unloaded
import done in AL32UTF8 character set and AL16UTF16 NCHAR character set
export done in JA16EUC character set and AL16UTF16 NCHAR character set
Warning: possible data loss in character set conversions
Starting "SYSTEM"."SYS_IMPORT_SCHEMA_01":  SYSTEM/******** SCHEMAS=SCOTT DIRECTORY=dir1 DUMPFILE=expdat.dmp data_options=REJECT_ROWS_WITH_REPL_CHAR
Processing object type SCHEMA_EXPORT/USER
Processing object type SCHEMA_EXPORT/SYSTEM_GRANT
Processing object type SCHEMA_EXPORT/DEFAULT_ROLE
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/SEQUENCE/SEQUENCE
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
ORA-02374: conversion error loading table "SCOTT"."DATA1"
ORA-39347: Character data loss was detected during conversion, the row was rejected.

ORA-02372: data for row: C1 : 0X'ADA1'

. . imported "SCOTT"."DATA1"                            5.015 KB       1 out of 1 rows
Processing object type SCHEMA_EXPORT/VIEW/VIEW
Job "SYSTEM"."SYS_IMPORT_SCHEMA_01" successfully completed at Mon Nov 20 12:26:21 2017 elapsed 0 00:00:06

```