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