Last update 2006.10.24
Tomcat でServlet の開発をしていると、データベースにアクセスする必要などがでてきます。
PostgreSQLを使って開発をしていたのですが、いくつか動作のよくなさそうな点が出てきたので、直してみました。
ここには、PostgreSQL7.0.3用の日本語/多言語対応JDBCドライバ、PostgreSQL7.3.4/7.4.2用 Sun ONE Studio対応JDBCドライバの2種類があります。
最新のJDBCドライバは、オフィシャルなもので問題ないので作っていません。
もくじ?
順番ばらばら・・・
最新版はもうこちらでは作っていません。オフィシャルなものを使ってください。
PostgreSQL 7系までは、integer型に文字列を入れても数字的なものであれば自動的に型変換してくれました。8系になってからは、この型変換をしてくれないのでJDBCのPreparedStatement などではまってしまうかもしれません。ふつうにSQL文を書くだけなら、型変換してくれます。
create table foo (a int, b int);
PreparedStatement st = con.prepareStatement("insert into
foo (a,b) values('123','456')");
st.execute();
PreparedStatement st = con.prepareStatement("insert into
foo (a,b) values(?, ?)");
st.setInt(1,123);
st.setString(2,"456"); // この変換がうまくできない
st.execute();
aとbがどちらもintegerだったとしましょう。上のプログラムはなんとなく動き、下のプログラムはなんとなく動いてくれません。上のような直にデータをSQL中に埋めてしまうプログラムはSQLインジェクションなどで脆弱です。下のようにするには、SQLのtext やJavaのString などの文字列からintegerへのキャストを許可してやる必要があったりなかったり。
create cast (text as integer) with function int4(text);
のようなものが必要なんでしょうか? もともとあるのでできない? または
con.prepareStatement("insert into foo (a, b) values(cast (? as int), cast (? as int))");
的に明示的なcastを指定します。これはできるようです。
とりあえず以前と同じように使う方法は謎です。
参考
7.4.5対応のものを作りました。エラーメッセージが一つ増えていたのでその訳も追加。コードの変更は従来通り。
修正箇所はPostgreSQL 7.4のものと同じですが、元のJDBCドライバに修正が含まれているようですので、PostgreSQL 7.4.2、7.4.3、7.4.5ではこちらをお使いください。変更点はSRAのサイトなどを参照してみてください。→PostgereSQL 7.4.2から7.4.3の変更点
PostgreSQL7.4のときと修正点は同じです。PostgreSQL7.4のJDBCドライバではPostgreSQL7.4.2で不具合が起きる場合があるようですのでこちらをお使いください。
# tar zxvf postgresql-7.4.3.tar.gz
# cd postgresql-7.4.3
#
patch -p1<../postgresql-7.4.3-jdbc.patch
動作確認
J2SDK | 環境 | PostgreSQL | JDBCドライバ | 動作 |
---|---|---|---|---|
1.4.2_04 | NetBeans IDE ja 3.6 | 7.4.2 EUC | jdbc.postgresql.org 7.4 214 | ○ |
PostgreSQL src 7.4.2 | ? | |||
しいしせねっと7.4.2 | ○ | |||
1.4.2_04 | Java Studio 6 Enterprise 2004Q1 |
7.4.2 EUC | jdbc.postgresql.org 7.4 214 | × |
PostgreSQL src 7.4.2 | × | |||
しいしせねっと7.4.2 | ○ |
テスト項目 IDEの実行時タブで、テーブルなどが表示できること
EJBが使えること(未実施)
NetBeans IDEでは、この差分なしで使えるようですが、JDBCドライバの動作は修正しておいた方がいいかもしれません。
動作確認報告ください。
未確認項目
不具合報告
Javaのjre/lib/ext ディレクトリ(JDK用("c:\j2sdk1.4.x"とJRE用("c:\Program Files\Java\..."の2つがありますが、Sun ONE Studioが使うのはJDK用)またはSunONE Studioのディレクトリ("c:\Program Files\s1studio\"のどこか?)です。そこへpostgresql.jarをコピーするだけ。
うまくいかない場合は別のPostgreSQL用JDBCドライバが残っていないことを確認してください。それでもうまくいかないときは、JDBCドライバを直してみます。
普段使う場合にどれを指定すればいいのか、ちょっとメモ
java.sql.Driver型のクラス(JDK1.1/J2SE用)
JNDIから利用できるjavax.sql.DataSource型のクラス(J2EE用、J2SE1.4からも利用可)
DataSourceが使えると、コネクションpoolなどができます。Tomcat 5のconfig.xmlでは自前のコネクションpoolを実装しているようなので、こちらは設定できないようです。たぶん。Java System Application Serverなどで使えます。
固有かどうかわかりませんが、JNDIに設定するDataSourceを使うためのプロパティ
プロパティ名 | 内容 | 例 |
---|---|---|
serverName | サーバ名 | db.example.com |
databaseName | データベース名 | testdb |
user | ユーザ名 | okome |
password | パスワード | password |
ssl | なくていい? SSLで接続したいときに設定します |
java.sql.DriverManager.getConnection("jdbc:postgresql://db.example.com/testdb?ssl=true","okome","password") と同じようなことができます。DataSource系でクライアント認証ができるかどうかは未検証。
SSLを使う設定でサーバが動いている場合のみ、?sslのオプションを使うことができます。 8系ドライバではssl=true にしましょう。
SSLの詳細は[PostgreSQL SSL]に書いてみました。
JDBCドライバのディレクトリは、postgresqlのsrc/interfaces/jdbc にあります。
そのファイルを日本語対応のものと入れ換えて、make jdbc2 でできた postgresql.jar ファイルを jre/lib/ext に置いたり、CLASSPATHを通したりします。
Class.forName("org.postgresql.Driver");
java.sql.DriverManager.getConnection("jdbc:postgresql:~",account,password);
と、PostgreSQL のJDBCドライバの設定そのままで使えます。
J2EE環境でmake する場合は、J2EEに対応したJDBCドライバが作られます。
違いはConnectionPool 関連だと思いますが、興味のある方は調べてみるといいのではないでせぅか。
# configure --with-java
# make
Java 2 SDKとJakarta-Ant が必要です。
注意
PostgreSQL 7.1以降のJDBCドライバは、標準で日本語にも対応していますので、日本語対応のためにこちらのJDBCドライバは必要ありません。
もし、問題があるようなら、再度作成します。Stringとbyteの変換で、たとえASCIIコードを想定したものであっても、文字コードの指定のないコードが1つでもあると、正しく動作しない場合があります。
JDBC3系の実装が、全般で不足しているようです。
DatabaseMetadata 系のJDBCドライバがどの機能をサポートしているか?
という根本的な部分がきちんと実装されていないようです。
DatabaseMetaData.getTables() scheme名の大文字小文字の違いについて、Sun ONE Studio(NetBeans?)では同一視している。(統一されていない)PostgreSQLでは区別している。対応済。
テーブル名等について、PostgreSQL本体は区別している。psqlコマンドでは小文字に統一されている? JDBCドライバでは区別される。区別すべきではない?
boolean / bit 型のString化について、Sun ONE Studioなどはtrue/false を期待値としているが、PostgreSQLはt/fで返す。対応済。
文字とバイト列の変換、まだ変ですね。StringクラスのgetBytes() は、引数なしで使ってはいけません。将来的にOSのデフォルトエンコードがUTF-16などのときに誤変換してしまいます。org.postgresql.core.Encodingクラスが用意されているので、Encoding.encode()に全て置き換えましょう。
EUC-JP系DBについては、MS系Unicodeと標準Unicode、両方に変換できるようにしてみましょうか。7.3系JDBCドライバではMS系Unicode、7.2系JDBCドライバでは標準Unicodeに変換されます。
Java 2 SDK 1.4では、一部のクラスが中途半端に存在するため、PostgreSQL7.2.xのJDBCドライバをmakeすることができません。
Java 2 SDK 1.3 等では作成することができますので、一時的にjava 2 SDK 1.3をインストールして PostgreSQLのJDBCドライバをmake
してみてください。
PostgreSQL7.3で、この問題は修正されています。
7.3.4版で実験した結果を7.4のJDBCドライバに反映。変更点を最小にしてみた。schema等の大文字小文字を同一とみなす点とResultSet.getString()でboolean型(bit型)のデータをString型で取得するときの戻り値の修正。
こちらはSun ONE Studio 4または5に対応する程度の機能を実装しようとしているものです。
日本語対応は、一応普通に利用する範囲ではできているようですが、完全ではないのかも。7.0.3までの変更は反映していません。PostgreSQL6系ドライバは、変更していません。
文字コードなのですが、Shift_JIS(のUnicode対応表)について2種類あることが、PostgreSQLでも影響する可能性があります。Java、その他でWindows-31J(MS互換Unicode)とShift_JISやEUC-JP(標準Unicode)では"~"などの文字位置がUnicode上で異なります。
シフトJIS全般のテキストをデータベースに入れる場合など、Unicode上で~などの文字がどちらのコードの文字になっているかを意識する必要があります。文字コードの墓場参照
PostgreSQL 7.3.x系のJDBCドライバを使う場合は、PostgreSQL上のEUC-JPの文字がWindows-31Jと互換のあるMS互換Unicode上の位置にマップされます。7.2.x以前にはShift_JIS互換文字(標準Unicode)でした。Windows上の各種入出力もWindows-31J側にあわせられているので、Javaからのファイル等への入出力にはShift_JISを使わずにWindows-31J(MS932)を使うことをおすすめします。EUC-JP、Shift_JISのファイル等に出力する場合には注意が必要です。ソフトウェア全体でどちらかに統一しましょう。WindowsならWindows-31Jでよいのですが、Linuxの場合はEUC-JPとWindows-31JのUnicode上の位置が一部異なるので難しいところです。
last update 2003.01.20
Javaの内部コードはUNICODEだからです。
String
にUNICODE以外の文字を入れるのは、そもそもの間違いであり、データベースからの文字は、まずUNICODEに変換してアプリケーションに渡す必要があります。逆の場合もおなじことです。
一度は全て修正したのですが、JDBCドライバの中(に限らず)、いくつか文字コードを指定しないでString型とbyte型を変換している部分がまだあるかもしれません。これは、OSのデフォルト文字コードにたよっているということなので、WindowsとLinuxなど、デフォルト文字コードが違うところで使うことを想定すると、たとえASCIIコードのみの変換でも、あってはいけないことです。もし、OSのデフォルト文字コードがUNICODE(UTF-16)などのOSがあった場合にどうなってしまうのか考えてみてください。JDBCドライバは、ネットワーク上の相手のデータベースとJavaの間で文字コード変換をするのであって、OSの文字コードは一切関係ないのです。
TomcatなどのWebアプリケーションと組み合わせる場合、WebとJavaとで文字コードがうまく変換できているかも注意が必要です。
UNICODE DBに対して psql コマンドを使うときなども、telnetなどがUTF-8の文字コードになっていないと使えないです。ODBCドライバも対応していないかもしれません。emacs 経由などでUNICODE DBにアクセスする方法はあるようです。
参考にさせていただいたり、サーチエンジンで検索していて見付けたPostgreSQL JDBCドライバの日本語化に関するページです。
承諾なしでリンクさせていただいています。
psqlODBCも各所にあるのですね。PostgreSQLユーザ会にリンクがないのでメモ