001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.db; 017 018import java.io.IOException; 019import java.io.Reader; 020import java.sql.CallableStatement; 021import java.sql.Clob; 022import java.sql.Connection; 023import java.sql.PreparedStatement; 024import java.sql.ParameterMetaData; 025import java.sql.ResultSet; 026import java.sql.ResultSetMetaData; 027import java.sql.SQLException; 028import java.sql.Types; 029import java.util.ArrayList; 030import java.util.Locale; 031 032import org.opengion.fukurou.util.ApplicationInfo; 033import org.opengion.fukurou.util.Closer; 034import org.opengion.fukurou.util.StringUtil; 035import org.opengion.fukurou.util.HybsDateUtil; 036 037/** 038 * データベース関連の便利なメソッドを集めた簡易ユーティリティークラスです。 039 * 全てのメソッドは、static メソッドになっています。 040 * 041 * @og.rev 2.1.1.1 (2002/11/15) Serializable インターフェースを削除する。 042 * @og.rev 4.0.0.0 (2007/10/16) DBアクセス関係のメソッドのみをパッケージ移動(hayabusa/db ⇒ fukurou/db) 043 * @og.group DB/Shell制御 044 * 045 * @version 4.0 046 * @author Kazuhiko Hasegawa 047 * @since JDK5.0, 048 */ 049public final class DBUtil { 050 051 /** システム依存の改行記号をセットします。4.0.0.0(2007/10/17) */ 052 private static final String CR = System.getProperty( "line.separator" ); 053 054 /** 055 * インスタンスを作らないので、コンストラクタは、private に設定します。 056 */ 057 private DBUtil() {} 058 059 /** 060 * 初期データベースに接続して、Queryを実行します(互換性確保のため残しています)。 061 * 062 * ステートメントと引数により、Prepared クエリーの検索のみ実行します。 063 * 結果は,すべて文字列に変換されて格納されます。 064 * 065 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 066 * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 067 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。 068 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 069 * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 070 * 071 * @param stmt ステートメント文字列 072 * @param args オブジェクトの引数配列 073 * @param appInfo アプリ情報オブジェクト 074 * 075 * @return 検索結果の配列 076 */ 077 public static String[][] dbExecute( final String stmt ,final String[] args ,final ApplicationInfo appInfo ) { 078 Transaction tran = new TransactionReal( appInfo ); // 5.3.7.0 (2011/07/01) 引数変更 079 080 // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 081 try { 082 return dbExecute( stmt, args, tran, null, false ); 083 } 084 finally { 085 // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。 086 tran.close(); 087 } 088 } 089 090 /** 091 * 初期データベースに接続して、Queryを実行します(Transaction 対応)。 092 * 093 * ステートメントと引数により、Prepared クエリーの検索のみ実行します。 094 * 結果は,すべて文字列に変換されて格納されます。 095 * ここでは、Transactionオブジェクトから、Connection を取り出して使用します。 096 * 097 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応 098 * 099 * @param stmt ステートメント文字列 100 * @param args オブジェクトの引数配列 101 * @param tran Transactionオブジェクト 102 * 103 * @return 検索結果の配列 104 */ 105 public static String[][] dbExecute( final String stmt ,final String[] args ,final Transaction tran ) { 106 return dbExecute( stmt, args, tran, null, false ); 107 } 108 109 /** 110 * 検索するデータベースを指定して、Queryを実行します(互換性確保のため残しています)。 111 * 112 * ステートメントと引数により、Prepared クエリーの検索のみ実行します。 113 * 結果は,すべて文字列に変換されて格納されます。 114 * 追加:検索以外のSQLも実行できます。結果は、null を返します。 115 * 116 * @og.rev 3.0.0.0 (2002/12/25) 検索のみのクエリーから、何でもありのクエリーに変更 117 * @og.rev 2.3.1.3 (2003/01/28) Open Cursor が、大量に残る件の対応。ResultSet を close() 118 * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ+Queryに変更します。 119 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 120 * @og.rev 4.0.0.1 (2007/12/03) try ~ catch ~ finally をきちんと行う。 121 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。 122 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 123 * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 124 * 125 * @param stmt ステートメント文字列 126 * @param args オブジェクトの引数配列 127 * @param appInfo アプリ情報オブジェクト 128 * @param dbid 接続先ID 129 * 130 * @return 検索結果の配列 131 */ 132 public static String[][] dbExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo, final String dbid ) { 133 Transaction tran = new TransactionReal( appInfo ); // 5.3.7.0 (2011/07/01) 引数変更 134 135 // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 136 try { 137 return dbExecute( stmt, args, tran, dbid, false ); 138 } 139 finally { 140 // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。 141 tran.close(); 142 } 143 } 144 145 /** 146 * 検索するデータベースを指定して、Queryを実行します(Transaction 対応)。 147 * 148 * ステートメントと引数により、Prepared クエリーの検索のみ実行します。 149 * 結果は,すべて文字列に変換されて格納されます。 150 * 追加:検索以外のSQLも実行できます。結果は、null を返します。 151 * ここでは、Transactionオブジェクトから、Connection を取り出して使用します。 152 * 153 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応 154 * 155 * @param stmt ステートメント文字列 156 * @param args オブジェクトの引数配列 157 * @param tran Transactionオブジェクト 158 * @param dbid 接続先ID 159 * 160 * @return 検索結果の配列 161 */ 162 public static String[][] dbExecute( final String stmt ,final String[] args, final Transaction tran , final String dbid ) { 163 return dbExecute( stmt, args, tran, dbid, false ); 164 } 165 166 /** 167 * 検索するデータベースを指定して、Queryを実行します(互換性確保のため残しています)。 168 * 169 * ステートメントと引数により、Prepared クエリーの検索のみ実行します。 170 * 結果は,すべて文字列に変換されて格納されます。 171 * 追加:検索以外のSQLも実行できます。結果は、null を返します。 172 * 173 * @og.rev 4.3.7.0 (2009/06/01) 新規作成 174 * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応) 175 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。 176 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 177 * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 178 * 179 * @param stmt ステートメント文字列 180 * @param args オブジェクトの引数配列 181 * @param appInfo アプリ情報オブジェクト 182 * @param dbid 接続先ID 183 * @param useHeader 1行目にヘッダーを含めるか 184 * 185 * @return 検索結果の配列 186 */ 187 public static String[][] dbExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo, final String dbid, final boolean useHeader ) { 188 Transaction tran = new TransactionReal( appInfo ); // 5.3.7.0 (2011/07/01) 引数変更 189 190 // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 191 try { 192 return dbExecute( stmt, args, tran, dbid, useHeader ); 193 } 194 finally { 195 // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。 196 tran.close(); 197 } 198 } 199 200 /** 201 * 検索するデータベースを指定して、Queryを実行します(Transaction 対応)。 202 * 203 * ステートメントと引数により、Prepared クエリーの検索のみ実行します。 204 * 結果は,すべて文字列に変換されて格納されます。 205 * 追加:検索以外のSQLも実行できます。結果は、null を返します。 206 * 207 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応 208 * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。 209 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応 210 * 211 * @param stmt ステートメント文字列 212 * @param args オブジェクトの引数配列 213 * @param tran Transactionオブジェクト 214 * @param dbid 接続先ID 215 * @param useHeader 1行目にヘッダーを含めるか 216 * 217 * @return 検索結果の配列 218 */ 219 public static String[][] dbExecute( final String stmt ,final String[] args, final Transaction tran, final String dbid, final boolean useHeader ) { 220 PreparedStatement pstmt = null; 221 ResultSet resultSet = null; 222 String[][] rtn = null; 223 try { 224 Connection conn = tran.getConnection( dbid ); // 5.1.9.0 (2010/08/01) Transaction 対応 225 pstmt = conn.prepareStatement( stmt ); 226 if( args != null ) { 227 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応) 228 boolean useParamMetaData = ConnectionFactory.useParameterMetaData( dbid ); // 5.3.8.0 (2011/08/01) 229 if( useParamMetaData ) { 230 ParameterMetaData pMeta = pstmt.getParameterMetaData(); 231 for( int i=0; i<args.length; i++ ) { 232 int type = pMeta.getParameterType( i+1 ); 233 // 5.3.8.0 (2011/08/01) setNull 対応 234 String val = args[i]; 235 if( val == null || val.isEmpty() ) { 236 pstmt.setNull( i+1, type ); 237 } 238 else { 239 pstmt.setObject( i+1, val, type ); 240 } 241 } 242 } 243 else { 244 for( int i=0; i<args.length; i++ ) { 245 pstmt.setObject( i+1,args[i] ); 246 } 247 } 248 } 249 boolean status = pstmt.execute(); 250 if( status ) { 251 resultSet = pstmt.getResultSet(); 252 rtn = DBUtil.resultToArray( resultSet,useHeader ); // 4.3.7.0 (2009/06/01) 253 } 254 else { 255 tran.commit(); // 5.1.9.0 (2010/08/01) Transaction 対応 256 } 257 } 258 catch ( SQLException ex ) { 259 tran.rollback(); // 5.1.9.0 (2010/08/01) Transaction 対応 260 String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR 261 + "SQL=[" + stmt + "]" + CR 262 + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR 263 + "DBID=[" + dbid + "]" + CR; 264 throw new RuntimeException( errMsg,ex ); 265 } 266 finally { 267 Closer.resultClose( resultSet ); 268 Closer.stmtClose( pstmt ); 269 } 270 return rtn; 271 } 272 273 /** 274 * 初期データベースに接続して、CallableStatement(PL/SQL)を実行します(互換性確保のため残しています)。 275 * ステートメントと引数により、CallableStatement クエリーを実行します。 276 * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に 277 * 設定して返します。 278 * ステートメント文字列には、 { call PLSQL( ?,?,?・・・ ) } となります。 279 * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。 280 * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。 281 * 282 * @og.rev 3.8.0.0 (2005/06/07) 新規追加 283 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 284 * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更 285 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。 286 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 287 * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 288 * 289 * @param stmt ステートメント文字列 290 * @param args オブジェクトの引数配列 291 * @param appInfo アプリ情報オブジェクト 292 * 293 * @return 実行結果([0]=ステータス、[1]=エラーメッセージ 294 */ 295 public static String[] dbCallExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo ) { 296 Transaction tran = new TransactionReal( appInfo ); // 5.3.7.0 (2011/07/01) 引数変更 297 298 // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 299 try { 300 return dbCallExecute( stmt ,args, tran, null ); 301 } 302 finally { 303 // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。 304 tran.close(); 305 } 306 } 307 308 /** 309 * 初期データベースに接続して、CallableStatement(PL/SQL)を実行します(Transaction 対応)。 310 * ステートメントと引数により、CallableStatement クエリーを実行します。 311 * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に 312 * 設定して返します。 313 * ステートメント文字列には、 { call PLSQL( ?,?,?・・・ ) } となります。 314 * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。 315 * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。 316 * 317 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応 318 * 319 * @param stmt ステートメント文字列 320 * @param args オブジェクトの引数配列 321 * @param tran Transactionオブジェクト 322 * 323 * @return 実行結果([0]=ステータス、[1]=エラーメッセージ 324 */ 325 public static String[] dbCallExecute( final String stmt ,final String[] args, final Transaction tran ) { 326 return dbCallExecute( stmt ,args, tran, null ); 327 } 328 329 /** 330 * 検索するデータベースを指定して、CallableStatement(PL/SQL)を実行します(互換性確保のため残しています)。 331 * ステートメントと引数により、CallableStatement クエリーを実行します。 332 * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に 333 * 設定して返します。 334 * ステートメント文字列には、 { call PLSQL( ?,?,?・・・ ) } となります。 335 * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。 336 * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。 337 * 検索するデータベースは、DEFAULT です。 338 * 339 * @og.rev 3.8.0.0 (2005/06/07) 新規追加 340 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 341 * @og.rev 4.0.0.1 (2007/12/03) try ~ catch ~ finally をきちんと行う。 342 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。 343 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 344 * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 345 * 346 * @param stmt ステートメント文字列 347 * @param args オブジェクトの引数配列 348 * @param appInfo アプリ情報オブジェクト 349 * @param dbid 接続先ID 350 * 351 * @return 実行結果([0]=ステータス、[1]=エラーメッセージ 352 */ 353 public static String[] dbCallExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo ,final String dbid ) { 354 Transaction tran = new TransactionReal( appInfo ); // 5.3.7.0 (2011/07/01) 引数変更 355 356 // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 357 try { 358 return dbCallExecute( stmt ,args, tran, dbid ); 359 } 360 finally { 361 // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。 362 tran.close(); 363 } 364 } 365 366 /** 367 * 検索するデータベースを指定して、CallableStatement(PL/SQL)を実行します(Transaction 対応)。 368 * ステートメントと引数により、CallableStatement クエリーを実行します。 369 * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に 370 * 設定して返します。 371 * ステートメント文字列には、 { call PLSQL( ?,?,?・・・ ) } となります。 372 * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。 373 * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。 374 * 検索するデータベースは、DEFAULT です。 375 * 376 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応 377 * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。 378 * 379 * @param stmt ステートメント文字列 380 * @param args オブジェクトの引数配列 381 * @param tran Transactionオブジェクト 382 * @param dbid 接続先ID 383 * 384 * @return 実行結果([0]=ステータス、[1]=エラーメッセージ 385 */ 386 public static String[] dbCallExecute( final String stmt ,final String[] args, final Transaction tran ,final String dbid ) { 387 CallableStatement callStmt = null ; 388 389 String[] rtn = new String[2] ; 390 391 try { 392 Connection conn = tran.getConnection( dbid ); // 5.1.9.0 (2010/08/01) Transaction 対応 393 callStmt = conn.prepareCall( stmt ); 394 395 callStmt.registerOutParameter( 1, Types.INTEGER ); 396 callStmt.registerOutParameter( 2, Types.VARCHAR ); 397 if( args != null ) { 398 for( int i=0; i<args.length; i++ ) { 399 callStmt.setObject( i+3,args[i] ); 400 } 401 } 402 callStmt.execute(); 403 404 rtn[0] = String.valueOf( callStmt.getInt(1) ); // 結果ステータス 405 rtn[1] = callStmt.getString(2); // 内容(エラーメッセージ) 406 407 tran.commit(); // 5.1.9.0 (2010/08/01) Transaction 対応 408 } 409 catch ( SQLException ex ) { 410 tran.rollback(); // 5.1.9.0 (2010/08/01) Transaction 対応 411 String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR 412 + "SQL=[" + stmt + "]" + CR 413 + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR 414 + "DBID=[" + dbid + "]" + CR; 415 throw new RuntimeException( errMsg,ex ); 416 } 417 finally { 418 Closer.stmtClose( callStmt ); 419 // 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。 420 } 421 return rtn; 422 } 423 424 /** 425 * SQL文の実行結果において、データの件数を取得します(互換性確保のため残しています)。 426 * ステートメントと引数により、Prepared クエリーの検索を実行します。 427 * 結果は、件数を数値で返します。 428 * あくまで、存在チェックに必要な処理のみ行っているため、通常の検索より高速です。 429 * 430 * @og.rev 3.5.0.0 (2003/09/17) 新規作成 431 * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ+Queryに変更します。 432 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 433 * @og.rev 4.0.0.1 (2007/12/03) try ~ catch ~ finally をきちんと行う。 434 * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応) 435 * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。 436 * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 437 * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 438 * 439 * @param stmt ステートメント文字列 440 * @param args オブジェクトの引数配列 441 * @param appInfo アプリ情報オブジェクト 442 * @param dbid 接続先ID 443 * 444 * @return 検索結果(データの件数) 445 */ 446 public static int dbExist( final String stmt ,final String[] args, final ApplicationInfo appInfo , final String dbid ) { 447 Transaction tran = new TransactionReal( appInfo ); // 5.3.7.0 (2011/07/01) 引数変更 448 449 // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。 450 try { 451 return dbExist( stmt ,args, tran , dbid ); 452 } 453 finally { 454 // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。 455 tran.close(); 456 } 457 } 458 459 /** 460 * SQL文の実行結果において、データの件数を取得します(Transaction 対応)。 461 * ステートメントと引数により、Prepared クエリーの検索を実行します。 462 * 結果は、件数を数値で返します。 463 * あくまで、存在チェックに必要な処理のみ行っているため、通常の検索より高速です。 464 * 465 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応 466 * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。 467 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応 468 * 469 * @param stmt ステートメント文字列 470 * @param args オブジェクトの引数配列 471 * @param tran Transactionオブジェクト 472 * @param dbid 接続先ID 473 * 474 * @return 検索結果(データの件数) 475 */ 476 public static int dbExist( final String stmt ,final String[] args, final Transaction tran , final String dbid ) { 477 PreparedStatement pstmt = null; 478 ResultSet resultSet = null; 479 int rtnCnt = -1; 480 481 try { 482 Connection conn = tran.getConnection( dbid ); // 5.1.9.0 (2010/08/01) Transaction 対応 483 pstmt = conn.prepareStatement( stmt ); 484 if( args != null ) { 485 // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応) 486 boolean useParamMetaData = ConnectionFactory.useParameterMetaData( dbid ); // 5.3.8.0 (2011/08/01) 487 if( useParamMetaData ) { 488 ParameterMetaData pMeta = pstmt.getParameterMetaData(); 489 for( int i=0; i<args.length; i++ ) { 490 int type = pMeta.getParameterType( i+1 ); 491 // 5.3.8.0 (2011/08/01) setNull 対応 492 String val = args[i]; 493 if( val == null || val.isEmpty() ) { 494 pstmt.setNull( i+1, type ); 495 } 496 else { 497 pstmt.setObject( i+1, val, type ); 498 } 499 } 500 } 501 else { 502 for( int i=0; i<args.length; i++ ) { 503 pstmt.setObject( i+1,args[i] ); 504 } 505 } 506 } 507 508 resultSet = pstmt.executeQuery(); 509 if( resultSet.next() ) { 510 rtnCnt = resultSet.getInt(1); 511 } 512 } 513 catch ( SQLException ex ) { 514 String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR 515 + "SQL=[" + stmt + "]" + CR 516 + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR 517 + "DBID=[" + dbid + "]" + CR; 518 throw new RuntimeException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並び順変更 519 } 520 finally { 521 Closer.resultClose( resultSet ); 522 Closer.stmtClose( pstmt ); 523 } 524 return rtnCnt; 525 } 526 527 /** 528 * ResultSet より、結果の文字列配列を作成します。 529 * 530 * 結果は,すべて文字列に変換されて格納されます。 531 * 移動したメソッドで使われているのでこれも移動 532 * 533 * @og.rev 3.1.0.0 (2003/03/20) Vector を使用している箇所で、非同期でも構わない箇所を、ArrayList に置換え。 534 * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ+Queryに変更します。 535 * @og.rev 4.0.0.0 (2005/01/31) private ⇒ public , ヘッダー情報の取得有無フラグの追加 536 * @og.rev 5.6.7.0 (2013/07/27) CLOB 対応 537 * 538 * @param resultSet ResultSetオブジェクト 539 * @param useHeader true:ヘッダーを第一行に含める/false:含めない 540 * 541 * @return ResultSetの検索結果配列 542 */ 543 public static String[][] resultToArray( final ResultSet resultSet,final boolean useHeader ) { 544 ArrayList<String[]> data = new ArrayList<String[]>(); 545 try { 546 ResultSetMetaData metaData = resultSet.getMetaData(); 547 int numberOfColumns = metaData.getColumnCount(); 548 549 String[] columnNames = new String[numberOfColumns]; 550 // 5.6.7.0 (2013/07/27) CLOB 対応 551 int[] type = new int[numberOfColumns]; 552 boolean useClob = false; // そもそも、CLOB系のカラムがあるかどうか 553 for( int i = 0; i < numberOfColumns; i++ ) { 554 int tp = metaData.getColumnType( i+1 ); 555 type[i] = tp ; 556 if( tp == Types.CLOB || tp == Types.ROWID || tp == Types.TIMESTAMP ) { useClob = true; } 557 if( useHeader ) { 558 columnNames[i] = metaData.getColumnLabel(i+1).toUpperCase(Locale.JAPAN) ; 559 } 560 } 561 562 if( useHeader ) { data.add( columnNames ); } 563 564 // 5.6.7.0 (2013/07/27) CLOB 対応。ついでに、ループカウンタを、0からに変更します。 565 while( resultSet.next() ) { 566 String[] columnValues = new String[numberOfColumns]; 567 for( int i = 0; i < numberOfColumns; i++ ) { 568 Object obj = resultSet.getObject(i+1); 569 if( obj == null ) { 570 columnValues[i] = ""; 571 } 572 else if( useClob ) { 573 columnValues[i] = getValue( resultSet, i ,type[i] ); 574 } 575 else { 576 columnValues[i] = String.valueOf( obj ); 577 } 578 } 579 data.add( columnValues ); 580 } 581 } 582 catch ( SQLException ex ) { 583 String errMsg = "処理結果を実行できませんでした。" 584 + CR + ex.getMessage() ; 585 throw new RuntimeException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並び順変更 586 } 587 588 int size = data.size(); 589 String[][] rtn = new String[size][]; 590 for( int i=0; i<size; i++ ) { 591 rtn[i] = data.get(i); 592 } 593 594 return rtn; 595 } 596 597 /** 598 * 検索結果オブジェクトから値を取り出します。 599 * 600 * @og.rev 5.3.6.0 (2011/06/01) 集計機能対応によりメソッド化 601 * @og.rev 5.5.5.4 (2012/08/18) if文をcase文に置き換え。 602 * @og.rev 5.5.5.4 (2012/08/18) TIMESTAMP の処理を追加。 603 * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。 604 * 605 * @param res 検索結果オブジェクト 606 * @param col カラム(0から始まる値。このメソッドの内部で、+1しています) 607 * @param type データタイプ(java.sql.Types.XXXX) 608 * 609 * @return 値 610 * @throws SQLException データベースアクセスエラー 611 */ 612 public static String getValue( final ResultSet res, final int col, final int type ) throws SQLException { 613 String val = null; 614 615 Object obj = res.getObject(col+1); 616 if( obj == null ) { 617 val = ""; 618 } 619 else { 620 switch( type ) { 621 case Types.CLOB : val = getClobData( (Clob)obj ) ; break; 622 case Types.ROWID: val = res.getString(col+1); break; 623 case Types.TIMESTAMP : val = HybsDateUtil.getDate( ((java.sql.Timestamp)obj).getTime() , "yyyyMMddHHmmss" ); break; 624 default : val = String.valueOf( obj ); 625 } 626 } 627 628 return val; 629 } 630 631 /** 632 * コネクションオブジェクトからデータベースのProductNameを取り出します。 633 * ProductName は、小文字化して返します。 634 * また、処理エラーが発生した場合は、"none" を返します。 635 * ここでは、SQLException は、発生させません。 636 * 637 * @og.rev 5.6.7.0 (2013/07/27) 新規追加 638 * @og.rev 5.6.7.4 (2013/08/30) ProductNameの小文字化対応 639 * 640 * @param conn コネクションオブジェクト 641 * 642 * @return データベースのProductName 643 */ 644 public static String getProductName( final Connection conn ) { 645 String dbName ; 646 try { 647 dbName = conn.getMetaData().getDatabaseProductName().toLowerCase( Locale.JAPAN ); // 5.6.7.4 (2013/08/30) 648 } 649 catch( SQLException ex ) { 650 dbName = "none"; 651 } 652 return dbName ; 653 } 654 655 /** 656 * Clob オブジェクトから文字列を取り出します。 657 * 658 * @og.rev 5.3.6.0 (2011/06/01) 新規作成 659 * 660 * @param clobData Clobオブジェクト 661 * 662 * @return Clobオブジェクトから取り出した文字列 663 * @throws SQLException データベースアクセスエラー 664 */ 665 private static String getClobData( final Clob clobData ) throws SQLException { 666 if( clobData == null ) { return ""; } 667 668 Reader reader = null; 669 StringBuilder buf = new StringBuilder( 10000 ); 670 671 try { 672 reader = clobData.getCharacterStream(); 673 char[] ch = new char[10000]; 674 int len ; 675 while( (len = reader.read( ch )) >= 0 ) { 676 buf.append( ch,0,len ); 677 } 678 } 679 catch( IOException ex ) { 680 String errMsg = "CLOBデータの読み込みに失敗しました。"; 681 throw new RuntimeException( errMsg,ex ); 682 } 683 finally { 684 Closer.ioClose( reader ); 685 } 686 return buf.toString(); 687 } 688}