プログラマとプロマネのあいだ

プログラマもやるし、プロマネもやるし、たまに似非アーキとか営業っぽいこともやるITエンジニアがスキルアップの話を中心に日常を綴るブログです。

java.sql.ParameterMetaDataの続き

ParameterMetaDataが取れると、何がうれしいのかというと、与えられたSQL文(?パラメータ付き)に適切なデフォルトパラメータを与えることができ、これによって、ひとまずSQLを投げてみることができます。そうすると、そこからあらゆるメタデータが取得できるわけで、その手のツールを作っている人にはうれしかったりするのです。まあ、今のところこれが出来るのはDB2だけなのですが。

ところで、ParameterMetaDataが取れないのであれば、想像で適当な値を入れてしまえと、少し乱暴なことを思いつきました。今のところ経験則では、"0"が一番エラーを起こす確率が低いようです。以下実験結果。

  • MSAccess2000 with JDBC-ODBCブリッジ
    • 全て"0"でok
  • hsqldb1.7.3@WindowsXP
    • "0"でokなところと、そうでないところあり、ただし、setString時点でエラーが発生するため、例外をキャッチした後、setIntやsetTimestampを行うことで回避できる
  • DB2 UDB v8@WindowsXP
    • "0"でokなところと、そうでないところあり。executeQuery時点でエラーが発生するため、救える余地なし。素直にParameterMetaDataを使った方が良さそう。
  • MSDE with SQL Server 2000 Driver for JDBC (MSDE with JDBC-ODBCブリッジ)@WindowsXP
    • "0"でokなところと、そうでないところあり。executeQuery時点でエラーが発生するため、救える余地なし。
  • Oracle10g@AIX
    • char, varchar, number, dateは"0"でいける。あとは試してない。多分、Oracle9iと一緒。
  • Oracle9i@WindowsXP
    • long, clob, nclob, blob, bfile以外は"0"でいける。executeQuery時点でエラーが発生するため、救える余地なし。まあ、あんまり使わない型だからいいか。。
  • Mysql3.23.53@WindowsXP with MySQL Connector/J 2.0.14 (サイトが混みあっていたようで、最新落とせなかったので、ちょい古いですが。。。)
    • 全ての型が"0"でいける。型変換がかしこい!

tinyint/smallint/mediumint/integer/bigint/float/double/decimal/numeric/date/datetime/timestamp/timeyear/char/bit/bool/tinyblob/tinytext/blob/text/mediumblob/mediumtext/longblob/longtext

まあ、そんなに型を暗黙で変換してはくれないということですね。

MSDEでのテストコード

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Test
{
	private static final String[] types = {
		"bigint",
		"int",
		"smallint",
		"tinyint",
		"bit",
		"decimal",
		"numeric",
//		"money",
//		"smallmoney",
		"float",
		"real",
//		"datetime",
//		"smalldatetime",
		"char",
		"varchar",
//		"text",
		"nchar",
		"nvarchar",
//		"ntext",
		"binary",
		"varbinary",
//		"image",
		"sql_variant",
//		"timestamp",
//		"uniqueidentifier"
	};

	public static void main(String[] args) throws Exception
	{
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try
		{
			Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
			con = DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433;SelectMethod=cursor", "sa", "sa123");
			//Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
			//con = DriverManager.getConnection("jdbc:odbc:sqlsvr1", "sa", "sa123");

			// 全ての型について、=条件文を設定する
			String sqlBase = "select * from test where 1=1";
			for(int i=0; i<types.length; i++)
			{
				sqlBase += " AND " + types[i] + "1 = ? ";
			}

			// 全ての条件に対し、String"0"を設定する
			stmt = con.prepareStatement(sqlBase);
			for(int i=0; i<types.length; i++)
			{
				stmt.setString((i+1), "0");
			}
			rs = stmt.executeQuery();
		}
		catch(SQLException e)
		{
			e.printStackTrace();
			throw e;
		}
		finally
		{
			if(rs != null)
			{
				rs.close();
			}
			if(stmt != null)
			{
				stmt.close();
			}
			if(rs != null)
			{
				rs.close();
			}
		}
	}
}