2007/12/06

Oracle 10g Express Edition でチト困った

Oracle 10g Express Edition は

  • AL32UTF8
  • WE8MSWIN1252

のみのCHARACTER SETしか使用できない

資料:
Oracle® Database Express Edition
10 Oracle Database XE Character and Language Configurations


これで非常に困った。

現在数社で連携をとってWebアプリを開発しているのだけど、
他社が作った機能の検証用テストデータとしてINSERT文が書かれたSQLファイルを送付してもらった。

いざINSERTしてみると、
ORA-12899:
列"hoge"."foo"."bar"の値が大きすぎます
(実際: 60、最大: 40)

とOracleに怒られ、データが入らない箇所がある。

慌てて文字数をカウントしたが、データに間違いはない。

これはなんだ?と思ったところで、
思い当たったのが、DBモデルのバージョンが違うのではないか?ということ

誤解を招く言い方かもしれないので補足を書くと、
上記の違いとはDBのバージョンが違うという意味ではない、
今回のプロジェクトでは(あってはならないことなんだけども)、
客先要求の追加などで、テーブルの名前が変わったり、テーブル自体が消えてたりなどの数回のモデルチェンジが行われているのだ。

そして何度かデータの最大文字数も変更されている。

数社で連携をとって開発している中でのモデルチェンジだったので、
もしかしたら各社でバージョンが違うのではないのか?
そのバージョンでは文字数定義が違うのではないか?と思った。

細かい敬意を省くために結果を述べると「モデルのバージョンは同じ」だった。

原因は弊社と他社のDBの差にあったのだ。


私の会社ではWindows版のOracle10gサーバーが見つからなかったので、
他社検証用として急いでOracle10g Express Editionを導入した。

無料で使える10gということでワクワクしながら環境構築していったのだが、
構築過程でサービス名が一つしか設定できないことを知る。

まぁこれは、今回プロジェクト限りで潰してもいいDBなので、問題はない。


それから上記の問題の発生である。
XEのインストールウィザードで文字コードの選択が出てこなかったので考えてなかったのだけど
(浅薄だなぁ・・・)

文字コードの差が問題だということが結果としてわかった。

現在Oracle10g正式版は何種類かの文字コードをカバーしている。
そしてデフォルトインストールすると、文字コードはSHIFT_JIS(JA16SJIS)になるのだが、

10gXEはUTF8(AL32UTF8)がデフォルトだ、
仕様書 を見ると、WE8MSWIN1252というコードも選択出来るそうなのだがこの文字コード自体初見である。

じゃあ、何が困るのか?

プログラマな人はとっくに原因なんて分かっていると思うけど、
プログラマじゃない人も世の中にはいるわけで・・・説明を続けると、

どうやら今回のプロジェクトにおいて10gを使用している所はすべてSHIFT_JISで設計されている。
(日本国内のイントラネット的なWebシステムなのでこれはまぁ、いいんじゃないかな・・・怒る人もいるだろうけど)


そうすると型VARCHAR2での日本語全角20文字MAX文字数の設計のは

VARCHAR2 = 40[Byte]

これは日本語の出力には2byte分のデータが必要なので文字数2倍としただけである。


さて、DBのCHARACTER SETがUTF8だった場合。
日本語全角20文字は
VARCHAR2 = 60[byte]

となる。UTF8はマルチバイト文字であり、
多言語をカバーするため1byte文字以外の出力に2~6byte分のデータが必要になる。
日本語の全角文字に必要なデータは3byteである。
よって文字数3倍とした。

さて、私は10gXEと10g正式版の違いを意識せずに提供されたCreateTable文を走らせた。


条件は揃ったので、最初の問題に戻ろう。

SHIFT_JISで設計されたテーブルデータをUTF810gXEにCreateし、
全角20文字のDBのフィールド用に作られたテストデータをINSERT文で突っ込むと、

DB側は設計上VARChAR2(40byte)という情報と、
入力された全角20文字のテストデータを見比べて

全角20文字を60byteデータと解釈し、入力者側に

ORA-12899:
列"hoge"."foo"."bar"の値が大きすぎます
(実際: 60、最大: 40)


というエラーを返す。


結論 : こっちが悪い。

0 件のコメント:

コメントを投稿