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