[pgsql-jp: 33830] Re: Java JDBCにおけるFloat 型のNaN値の扱いについて

bxcel bxcel @ prophet.jp
2004年 8月 6日 (金) 15:06:09 JST


松本と申します。

この件について以下のようなjdbcドライバのpatchを作ってみました。
postgres-7.4.3用です。 このpatchを適用したドライバを使用すると

ps = connection.prepareStatement("INSERT INTO t1 VALUES(?);");
ps.setObject(1,new Float(Float.NaN));

というコードの時に

INSERT INTO t1 VALUES('NaN');

というSQL文になります。

単純にNaNの時にsetStringと同じ処理になるようにしただけでして
その周りの処理はあまり理解できていません。
ローカル環境では確認出来ましたが、何かご意見等ございましたら
アドバイス頂きたくよろしくお願いします。

diff -rc jdbc.orig/org/postgresql/jdbc1/AbstractJdbc1Statement.java jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
*** jdbc.orig/org/postgresql/jdbc1/AbstractJdbc1Statement.java	2004-05-18 05:38:56.000000000 +0900
--- jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java	2004-08-06 14:24:10.000000000 +0900
***************
*** 1066,1072 ****
  	 */
  	public void setFloat(int parameterIndex, float x) throws SQLException
  	{
! 		bind(parameterIndex, Float.toString(x), PG_FLOAT);
  	}
  
  	/*
--- 1066,1076 ----
  	 */
  	public void setFloat(int parameterIndex, float x) throws SQLException
  	{
! 		if ((Float.isNaN(x)) || (x == Float.POSITIVE_INFINITY) || (x == Float.NEGATIVE_INFINITY)) {
! 			setString(parameterIndex, Float.toString(x), PG_TEXT);
! 		} else {
! 			bind(parameterIndex, Float.toString(x), PG_FLOAT);
! 		}
  	}
  
  	/*
***************
*** 1079,1085 ****
  	 */
  	public void setDouble(int parameterIndex, double x) throws SQLException
  	{
! 		bind(parameterIndex, Double.toString(x), PG_DOUBLE);
  	}
  
  	/*
--- 1083,1093 ----
  	 */
  	public void setDouble(int parameterIndex, double x) throws SQLException
  	{
! 		if ((Double.isNaN(x)) || (x == Double.POSITIVE_INFINITY) || (x == Double.NEGATIVE_INFINITY)) {
! 			setString(parameterIndex, Double.toString(x), PG_TEXT);
! 		} else {
! 			bind(parameterIndex, Double.toString(x), PG_DOUBLE);
! 		}
  	}
  
  	/*

> 松本と申します。
> 
> JDBC経由にてFloat型へデータをINSERTする処理において
> PreparedStatementを使用した場合、java.lang.Floatの値が
> Float.NaNの場合にエラーとなってしまいました。
> 
> 環境
>   Vine2.6 + postgres7.4.3 + pg74.214.jdbc3.jar
> 
> テーブル定義
>   test=# \d t1
>           テーブル "public.t1"
>    カラム |        型        | 修飾語
>   --------+------------------+--------
>    a      | double precision |
> 
> 再現用Javaのコード1
>   ps = connection.prepareStatement("INSERT INTO t1 VALUES(?);");
>   ps.setObject(1,new Float(Float.NaN));
> 
> 実行されたSQL文
>   INSERT INTO t1 VALUES(NaN);
> 
> 実行結果
>   ERROR:  column "nan" does not exist
> 
> 再現用Javaのコード2
>   ps.setFloat(1,Float.NaN);
> 
> 実行結果
>   ERROR:  column "nan" does not exist
> 
> psqlコマンドから実行してみた所、シングルクォートすると
> うまく行きました。
>   test=# INSERT INTO t1 VALUES('NaN');
>   INSERT 17151 1
>   test=# select * from t1;
>     a
>   -----
>    NaN
>   (1 行)
> 
> Float.POSITIVE_INFINITYとFloat.NEGATIVE_INFINITY
> も同様でした。それぞれ
> 
> INSERT INTO t1 VALUES(Infinity);
> ERROR:  column "infinity" does not exist
> 
> INSERT INTO t1 VALUES(-Infinity);
> ERROR:  column "infinity" does not exist
> 
> となってしまいました。
> #もっとも解決したとしてもオーバーフローのようですが....
> 
> PreparedStatementの「?」を使用しなければ
> いいのですが、float型で使用できないのも不便ですし、
> 「NaN」や「Infinity」「-Infinity」の時だけ
> 別に展開するのもあまり良い方法には思えません。
> 
> 他に良い回避方法など何か情報ありましたら教えてください。
> 
> これとは似た別の問題ですが、「WHERE a = ?」というWHERE句にて
> 「ps.setObject(1,null)」とした場合「WHERE a = null」となって
> しまい「WHERE a is null」にはならないので、期待した結果に
> ならない問題と同様なんですかね。
> #こちらはSQL文作る方で対処しなければなりませんが....
> 
> 
> 



pgsql-jp メーリングリストの案内