No Bugs, No Life

読んだ本や、プログラミング、システム開発等のねたを中心に。文章を書く練習なので少し硬派に書くつもりだけど、どうなることやら。

Apache Derby インポートプロシージャ使用時の文字コード指定

MementoWeaver開発記
MWのデータ移行Pgmも(とりあえずAlbumだけは)ひとまず出来たので、出来たCSVDerbyにインポートしてみたが、またしても嵌ったので嵌りメモ。
自ら望んだとはいえ、毎回はまる...。

環境

Javaのバージョン

C:\Program Files\Java\jdk1.7.0_13\bin>java -version
java version "1.7.0_13"
Java(TM) SE Runtime Environment (build 1.7.0_13-b20)
Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)

ijのバージョン

C:\Program Files\Java\jdk1.7.0_13\db\bin>ij
ij バージョン 10.8

テーブル定義

色々再現したのはTagged_Material(タグ付素材)テーブル。
VARCHAR(256)のMEMOフィールドを中心に嵌った。
f:id:kazyury:20130511003336p:plain

嵌ったポイント

  • derbyへインポートが行えないデータが存在する
  • インポートに成功したデータが文字化けしている

確認結果

case 1

case case 1
テストデータ(utf-8) "20020307000020","album ","","2"
結果 OK
0000000: 2232 3030 3230 3330 3730 3030 3032 3022  "20020307000020"
0000010: 2c22 616c 6275 6d20 2020 222c 2222 2c22  ,"album   ","","
0000020: 3222 0d0a                                2"..

case 2

case case 2
テストデータ(utf-8) "20020307000019","album ","生まれた!","2"
結果 NG
0000000: 2232 3030 3230 3330 3730 3030 3031 3922  "20020307000019"
0000010: 2c22 616c 6275 6d20 2020 222c 22e7 949f  ,"album   ","...
0000020: e381 bee3 828c e381 9fef bc81 222c 2232  ............","2
0000030: 220d 0a                                  "..
  • 結果の詳細
    • ij
ij> call SYSCS_UTIL.SYSCS_IMPORT_DATA('MW','TAGGED_MATERIAL',NULL,NULL,'C:/Users/kazyury/devel/ruby20/mwmig/case2.csv',',','"',NULL,1);
エラー 38000: 式を評価している間に例外 'java.sql.SQLException: 列 'COLUMN4' は、FROM リスト内のどの表にもないか、結合仕様内にある一方でその結合仕様の範囲外であるか、または HAVING 文節内にある一方で GR
OUP BY リストに入っていない可能性があります。 これが CREATE または ALTER TABLE ステートメントの場合、'COLUMN4' はターゲット表内の列ではありません。' がスローされました。
エラー 42X04: 列 'COLUMN4' は、FROM リスト内のどの表にもないか、結合仕様内にある一方でその結合仕様の範囲外であるか、または HAVING 文節内にある一方で GROUP BY リストに入っていない可能性があります。 こ
れが CREATE または ALTER TABLE ステートメントの場合、'COLUMN4' はターゲット表内の列ではありません。
    • eclipse Data Source Explorerからのロード
Loading "MW"."TAGGED_MATERIAL"...
org.eclipse.datatools.sqltools.data.internal.core.load.DataFormatException: Unexpected token (found 2, expected ,)
Data loading failed.

case 3

case case 3
テストデータ(utf-8) "20020307000019","album ","生まれた","2"
結果 loadは成功。ただし、文字化け。
0000000: 2232 3030 3230 3330 3730 3030 3031 3922  "20020307000019"
0000010: 2c22 616c 6275 6d20 2020 222c 22e7 949f  ,"album   ","...
0000020: e381 bee3 828c e381 9f22 2c22 3222 0d0a  .........","2"..
  • 結果の詳細

f:id:kazyury:20130511114528p:plain

問題の原因

case2(第4フィールドのバイト数は15byte)でインポートデータのtoken区切りが誤っていること、及びcase3(第4フィールドのバイト数は12byte)で文字化けしてしまっていることから、ijがutf-8ファイルであることを認識せずに、2byte系のCodesetとして認識している様子。
Parameters for the import proceduresによると、文字コードを指定しなければデフォルトではJVMのCodesetと同様となるらしい。

CODESET
Specifies the code set of the data in the input file. The code set name should be one of the Java-supported character encoding sets. Data is converted from the specified code set to the database code set (UTF-8). You can specify a NULL value to interpret the data file in the same code set as the JVM in which it is being executed. The CODESET parameter takes an input argument that is a VARCHAR (128) data type.

http://db.apache.org/derby/docs/10.4/tools/rtoolsimport64241.html

確かにEclipseのencodingはMS932としているので、これが原因の様子。

対処

Eclipse Data Source Explorer からのロードでは、文字コード指定は行えない。
f:id:kazyury:20130511132710p:plain
面倒ではあるが、基本的には1回作業なのでijからデータロードを行うことにする。
(因みに上記の例ではSYSCS_UTL.SYSCS_IMPORT_DATAを使用したが、CSVの全列を表の全列に入れるので、SYSCS_UTL.SYSCS_IMPORT_TABLEで良い。引数も少なくて済むのでSYSCS_IMPORT_TABLEを使用することにする。)

インポートプロシージャのシンタックスはImporting data using the built-in proceduresを、利用可能なCodesetはCODESET values for import and export proceduresを参考にした(何れもhttp://db.apache.org/derby/docs/10.4以下のページ)。

C:\Program Files\Java\jdk1.7.0_13\db\bin>ij
ij バージョン 10.8
ij> connect 'jdbc:derby:C:\Users\kazyury\MyDB';
Sat May 11 13:40:48 JST 2013 Thread[main,5,main] java.io.FileNotFoundException: derby.log (アクセスが拒否されました。)
----------------------------------------------------------------
Sat May 11 13:40:49 JST 2013:
 Derby バージョン The Apache Software Foundation - Apache Derby - 10.8.2.2 - (1181258): インスタンス a816c00e-013e-91e4-27a4-00000181c938 を
クラスローダー sun.misc.Launcher$AppClassLoader@17f7be7b によってデータベースディレクトリ C:\Users\kazyury\MyDB  上でブート中


java.vendor=Oracle Corporation
java.runtime.version=1.7.0_13-b20
user.dir=C:\Program Files\Java\jdk1.7.0_13\db\bin
derby.system.home=null
データベースクラスローダーが開始されました - derby.database.classpath=''
ij> call SYSCS_UTIL.SYSCS_IMPORT_TABLE('MW','TAGGED_MATERIAL','C:/Users/kazyury/devel/ruby20/mwmig/case2.csv',',','"','UTF-8',1);
0 行が挿入/更新/削除されました
ij> disconnect;
ij> exit;
----------------------------------------------------------------
Sat May 11 13:42:55 JST 2013: Derby エンジンをシャットダウンしています
----------------------------------------------------------------
Sat May 11 13:42:55 JST 2013:
クラスローダー sun.misc.Launcher$AppClassLoader@17f7be7b を持つデータベースディレクトリ C:\Users\kazyury\MyDB のインスタンス a816c00e-013e-91e4-27a4-00000181c938 をシャットダウンしています
----------------------------------------------------------------
C:\Program Files\Java\jdk1.7.0_13\db\bin>

LibreOfficeのBaseから確認
f:id:kazyury:20130511134619p:plain

うむ、OKっぽい。