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.hayabusa.db; 017 018import java.sql.Connection; 019import java.sql.ResultSet; 020import java.sql.SQLException; 021 022import org.opengion.fukurou.system.HybsConst ; // 6.1.0.0 (2014/12/26) 023import org.opengion.fukurou.system.ThrowUtil; // 6.4.2.0 (2016/01/29) 024import org.opengion.fukurou.util.ErrorMessage; 025import org.opengion.hayabusa.common.HybsSystem; 026import org.opengion.hayabusa.common.HybsSystemException; 027import org.opengion.hayabusa.resource.ResourceManager; 028 029/** 030 * Query インターフェースを継承した Query の実装クラスです。 031 * クエリークラスにステートメントを与えて execute()することにより内部に DBTableModel を 032 * 作成します。 033 * このクラスは、Abstract クラスのため、実装は個々のサブクラスで行います。 034 * 唯一実装する必要があるのは, execute() メソッドだけです。 035 * 036 * @og.group DB検索 037 * @og.group DB登録 038 * 039 * @version 4.0 040 * @author Kazuhiko Hasegawa 041 * @since JDK5.0, 042 */ 043public class AbstractQuery implements Query { 044 /** システムの改行コードを設定します。*/ 045 protected static final String CR = HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 046 /** StringBilderなどの初期値を設定します。 {@value} */ 047 protected static final int BUFFER_MIDDLE = HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 048 049 private Connection connection ; 050 private int rtnCode = ErrorMessage.OK; 051 private ErrorMessage errMessage ; 052 private ResourceManager resource ; 053 054 private DBTableModel table ; 055 private String stmtString ; 056 private int executeCount = -1 ; 057 private int skipRowCount ; 058 private int maxRowCount = HybsSystem.sysInt( "DB_MAX_ROW_COUNT" ) ; 059 private boolean updateFlag = true ; 060 private DBEditConfig config ; // 5.3.6.0 (2011/06/01) 061 062 // 5.1.9.0 (2010/08/01) DB_RETRY_COUNT,DB_RETRY_TIME 廃止 063 /** データ検索時の最大処理制限時間 */ 064 protected static final int DB_MAX_QUERY_TIMEOUT = HybsSystem.sysInt( "DB_MAX_QUERY_TIMEOUT" ) ; 065 066 /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ {@value} */ 067 protected static final int DB_FETCH_SIZE = HybsConst.DB_FETCH_SIZE; // 6.9.4.1 (2018/04/09) 068 069// /** データ検索時のフェッチサイズを設定します。 */ 070// protected static final int DB_FETCH_SIZE = HybsConst.DB_FETCH_SIZE; // 6.9.4.1 (2018/04/09) 071 072 // 3.5.2.0 (2003/10/20) 内部オブジェクトタイプ名を システムパラメータ で定義します。 073 /** 内部オブジェクトタイプ名 {@value} */ 074 public static final String ARG_ARRAY = "ARG_ARRAY" ; 075 /** 内部オブジェクトタイプ名 {@value} */ 076 public static final String SYSARG_ARRAY = "SYSARG_ARRAY" ; 077 /** 内部オブジェクトタイプ名 {@value} */ 078 public static final String ERR_MSG = "ERR_MSG" ; 079 /** 内部オブジェクトタイプ名 {@value} */ 080 public static final String ERR_MSG_ARRAY = "ERR_MSG_ARRAY" ; 081 082 private String updQuery ; // 7.2.9.1 (2020/10/23) 083 private String insQuery ; // 7.2.9.1 (2020/10/23) 084 085 /** 086 * デフォルトコンストラクター 087 * 088 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 089 */ 090 protected AbstractQuery() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 091 092 /** 093 * Connectionオブジェクトを外部から設定します。 094 * 095 * 通常は、Transaction と 接続先(DBID) を使用して作成した Connection を渡します。 096 * このクラスでは、Connection の close() や、ConnectionFactory への返却なども 097 * 行いません。それらは、外部処理(通常は、Transactionオブジェクト)で行います。 098 * 099 * Connection には、null は登録できません。 100 * 101 * @og.rev 6.3.6.1 (2015/08/28) 新規追加 102 * 103 * @param conn Connectionオブジェクト 104 */ 105 public void setConnection( final Connection conn ) { 106 if( conn == null ) { 107 final String errMsg = "Connection に null は指定できません。" + CR ; 108 throw new HybsSystemException( errMsg ); 109 } 110 connection = conn; 111 } 112 113 /** 114 * ステートメント文字列をセットします。 115 * 116 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 117 * 118 * @param stmt ステートメント文字列 119 * 120 */ 121 public void setStatement( final String stmt ) { 122 this.stmtString = stmt.trim(); 123 } 124 125 /** 126 * ステートメント文字列を取り出します。 127 * 128 * @return ステートメント文字列 129 * 130 */ 131 public String getStatement() { 132 return stmtString; 133 } 134 135 /** 136 * ステートメント文字列(UPDATE,INSERT)をセットします。 137 * 138 * @og.rev 7.2.9.1 (2020/10/23) TableUpdateParamTag のマージ(UPDATE,INSERT)対応 139 * 140 * @param update UPDATEステートメント文字列 141 * @param insert INSERTステートメント文字列 142 */ 143 public void setMergeStatement( final String update , final String insert ) { 144 updQuery = update; 145 insQuery = insert; 146 } 147 148 /** 149 * ステートメント文字列(UPDATE,INSERT)を取り出します。 150 * 151 * @og.rev 7.2.9.1 (2020/10/23) TableUpdateParamTag のマージ(UPDATE,INSERT)対応 152 * @og.rev 7.2.9.3 (2020/11/06) 早い段階でエラーにしておきます。 153 * 154 * @return ステートメント文字列の配列(UPDATE,INSERTの順番) 155 * 156 */ 157 public String[] getMergeStatement() { 158 if( updQuery == null || insQuery == null ) { 159 final String errMsg = "Merge処理を行うには、INSERTとUPDATEの両方のQUERYが必要です。" + CR 160 + " updQuery=" + updQuery + CR 161 + " insQuery=" + insQuery + CR 162 + " query =" + stmtString ; 163 164 throw new UnsupportedOperationException( errMsg ); 165 } 166 167 return new String[] { updQuery,insQuery } ; 168 } 169 170 /** 171 * 引数配列付のクエリーを実行します。 172 * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。 173 * これは、PreparedQuery で使用する引数を配列でセットするものです。 174 * select * from emp where deptno = ? and job = ? などの PreparedQuery や 175 * { call xxxx( ?,?,? ) } などの CallableStatement の ? 部分の引数を 176 * 順番にセットしていきます。 177 * ※ このクラスでは実装されていません。 178 * 179 * @og.rev 6.1.1.0 (2015/01/17) 引数配列を可変引数にして、execute() を含めて定義します。 180 * 181 * @param args オブジェクトの引数配列(可変長引数) 182 */ 183 public void execute( final String... args ) { // 6.1.1.0 (2015/01/17) refactoring 184 final String errMsg = "このクラスでは実装されていません。execute( String... )"; 185 throw new UnsupportedOperationException( errMsg ); 186 } 187 188 /** 189 * 引数配列付のクエリーを実行します。 190 * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。 191 * これは、PreparedQuery で使用する引数を配列でセットするものです。 192 * select * from emp where deptno = ? and job = ? などの PreparedQuery の 193 * ? 部分の引数を 194 * 順番にセットしていきます。 195 * ※ このクラスでは実装されていません。 196 * 197 * @og.rev 4.0.0.0 (2005/01/31) 新規追加 198 * 199 * @param keys オブジェクトのキー配列 200 * @param args オブジェクトの引数配列(可変長引数) 201 */ 202 public void execute( final String[] keys, final String... args ) { // 6.1.1.0 (2015/01/17) refactoring 203 final String errMsg = "このクラスでは実装されていません。execute( String[],String... )"; 204 throw new UnsupportedOperationException( errMsg ); 205 } 206 207 /** 208 * 引数配列付のクエリーを実行します。 209 * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。 210 * これは、PreparedQuery で使用する引数を配列でセットするものです。 211 * select * from emp where deptno = ? and job = ? などの PreparedQuery の 212 * ? 部分の引数を 213 * 順番にセットしていきます。 214 * ※ このクラスでは実装されていません。 215 * 216 * @og.rev 4.0.0.0 (2005/01/31) 引数をすべて受け取って実行するメソッドを標準メソッドとして追加 217 * 218 * @param names カラム名(CSV形式) 219 * @param dbArrayType アレイタイプ名称 220 * @param sysArg DBSysArg配列 221 * @param userArg DBUserArg配列 222 */ 223 public void execute( final String names,final String dbArrayType, 224 final DBSysArg[] sysArg,final DBUserArg[] userArg ) { 225 final String errMsg = "このクラスでは実装されていません。execute( String,String,DBSysArg[],DBUserArg[] )"; 226 throw new UnsupportedOperationException( errMsg ); 227 } 228 229 /** 230 * 引数配列付のクエリーを実行します。 231 * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。 232 * これは、PreparedQuery で使用する引数を配列でセットするものです。 233 * select * from emp where deptno = ? and job = ? などの PreparedQuery の 234 * [カラム名] 部分の引数を、DBTableModelから順番にセットしていきます。 235 * ※ このクラスでは実装されていません。 236 * 237 * @param rowNo 選択された行番号配列(登録する対象行) 238 * @param table DBTableModelオブジェクト(登録する元データ) 239 */ 240 public void execute( final int[] rowNo, final DBTableModel table ) { 241 final String errMsg = "このクラスでは実装されていません。execute( final int[] rowNo, final DBTableModel table )"; 242 throw new UnsupportedOperationException( errMsg ); 243 } 244 245 /** 246 * クエリーの実行結果件数をセットします。 247 * 初期値は -1 です。(クエリーが失敗した場合や,CallableStatement の呼び出し等で 248 * 実行件数が明確でない場合の戻り値)。 249 * 250 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 251 * 252 * @param executeCount 実行結果件数 253 */ 254 protected void setExecuteCount( final int executeCount ) { 255 this.executeCount = executeCount; 256 } 257 258 /** 259 * クエリーの実行結果を返します。 260 * クエリーが失敗した場合や,CallableStatement の呼び出し等で実行件数が明確でない 261 * 場合は, -1 が返されます。 262 * 263 * @return 実行結果件数 264 */ 265 public int getExecuteCount() { 266 return executeCount; 267 } 268 269 /** 270 * DBTableModel をセットします。 271 * なお、検索系実行前に setDBTableModel() でテーブルをセットしていたとしても 272 * そのオブジェクトは破棄されて、新しい DBTableModel が生成されます。 273 * 274 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 275 * 276 * @param table DBTableModelオブジェクト 277 */ 278 protected void setDBTableModel( final DBTableModel table ) { 279 this.table = table; 280 } 281 282 /** 283 * 実行結果の DBTableModel を返します。 284 * 285 * @return DBTableModelオブジェクト 286 */ 287 public DBTableModel getDBTableModel() { 288 return table; 289 } 290 291 /** 292 * データベースの最大検索件数を返します。 293 * (初期値:DB_MAX_ROW_COUNT[={@og.value SystemData#DB_MAX_ROW_COUNT}])。 294 * データベース自体の検索は,指定されたSQLの全件を検索しますが, 295 * DBTableModelのデータとして登録する最大件数をこの値に設定します。0は無制限です。 296 * サーバーのメモリ資源と応答時間の確保の為です。 297 * 298 * @return 最大検索件数 299 */ 300 public int getMaxRowCount() { 301 return maxRowCount; 302 } 303 304 /** 305 * データベースの最大検索件数をセットします。 306 * データベース自体の検索は,指定されたSQLの全件を検索しますが, 307 * DBTableModelのデータとして登録する最大件数をこの値に設定します。 308 * サーバーのメモリ資源と応答時間の確保の為です。 309 * ゼロ、または、負の値を設定すると、無制限(Integer.MAX_VALUE)になります。 310 * 311 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 312 * @og.rev 4.0.0.0 (2005/08/31) ゼロ、または、負の値は、無制限(Integer.MAX_VALUE)にする。 313 * 314 * @param maxRowCount 最大検索件数 315 */ 316 public void setMaxRowCount( final int maxRowCount ) { 317 this.maxRowCount = maxRowCount > 0 ? maxRowCount : Integer.MAX_VALUE ; 318 } 319 320 /** 321 * データベースの検索スキップ件数を返します。 322 * データベース自体の検索は,指定されたSQLの全件を検索しますが, 323 * DBTableModelのデータとしては、スキップ件数分は登録されません。 324 * サーバーのメモリ資源と応答時間の確保の為です。 325 * 326 * @return 最大検索件数 327 */ 328 public int getSkipRowCount() { 329 return skipRowCount; 330 } 331 332 /** 333 * データベースの検索スキップ件数をセットします。 334 * データベース自体の検索は,指定されたSQLの全件を検索しますが, 335 * DBTableModelのデータとしては、スキップ件数分は登録されません。 336 * サーバーのメモリ資源と応答時間の確保の為です。 337 * 338 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 339 * 340 * @param skipRowCount スキップ件数 341 */ 342 public void setSkipRowCount( final int skipRowCount ) { 343 this.skipRowCount = skipRowCount; 344 } 345 346 /** 347 * アップデートフラグをセットします。 348 * これは、Query で更新処理の SQL 文を実行したときにセットされます。 349 * 更新処理が実行:true / 検索処理のみ:false をセットします。 350 * このメソッドを呼び出さない場合は、デフォルト:true です。 351 * 352 * @og.rev 2.1.2.3 (2002/12/02) データベース更新時に、更新フラグをセットするように変更 353 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 354 * 355 * @param up アップデートされたかどうか[true:更新処理/false:検索処理] 356 */ 357 protected void setUpdateFlag( final boolean up ) { 358 updateFlag = up; 359 } 360 361 /** 362 * アップデートフラグを取得します。 363 * これは、Query で更新処理の SQL 文を実行したときに true にセットされます。 364 * 更新処理が実行:true / 検索処理のみ:false を取得できます。 365 * 366 * @og.rev 2.1.2.3 (2002/12/02) データベース更新時に、更新フラグをセットするように変更 367 * @og.rev 4.0.0.0 (2007/07/20) メソッド名変更( getUpdateFlag() ⇒ isUpdate() ) 368 * 369 * @return アップデートされたかどうか[true:更新処理/false:検索処理] 370 */ 371 public boolean isUpdate() { 372 return updateFlag ; 373 } 374 375 /** 376 * リソースマネージャーをセットします。 377 * これは、言語(ロケール)に応じた DBColumn をあらかじめ設定しておく為に 378 * 必要です。 379 * リソースマネージャーが設定されていない、または、所定のキーの DBColumn が 380 * リソースに存在しない場合は、内部で DBColumn オブジェクトを作成します。 381 * 382 * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更 383 * 384 * @param resource リソースマネージャー 385 */ 386 public void setResourceManager( final ResourceManager resource ) { 387 this.resource = resource; 388 } 389 390 /** 391 * エラーコード を取得します。 392 * エラーコード は、ErrorMessage クラスで規定されているコードです。 393 * 394 * @return エラーコード 395 */ 396 public int getErrorCode() { 397 return rtnCode; 398 } 399 400 /** 401 * エラーコード をセットします。 402 * エラーコード は、ErrorMessage クラスで規定されているコードです。 403 * 404 * @param cd エラーコード 405 */ 406 protected void setErrorCode( final int cd ) { 407 rtnCode = cd; 408 } 409 410 /** 411 * エラーメッセージオブジェクト を取得します。 412 * 413 * @return エラーメッセージオブジェクト 414 */ 415 public ErrorMessage getErrorMessage() { 416 return errMessage; 417 } 418 419 /** 420 * エラーメッセージオブジェクト をセットします。 421 * 422 * @param em エラーメッセージオブジェクト 423 */ 424 protected void setErrorMessage( final ErrorMessage em ) { 425 errMessage = em; 426 } 427 428 /** 429 * 編集設定オブジェクトをセットします。 430 * 431 * @og.rev 5.3.6.0 (2011/06/01) 新規追加 432 * 433 * @param config 編集設定オブジェクト 434 */ 435 public void setEditConfig( final DBEditConfig config ) { 436 this.config = config; 437 } 438 439 /** 440 * 編集設定オブジェクトを取得します。 441 * 442 * @og.rev 5.3.6.0 (2011/06/01) 新規追加 443 * 444 * @return 編集設定オブジェクト 445 */ 446 protected DBEditConfig getEditConfig() { 447 return config; 448 } 449 450 ////////////////////////////////////////////////////////////////////////// 451 // 452 // 継承時にサブクラスから使用するメソッド類( protected ) 453 // 454 ////////////////////////////////////////////////////////////////////////// 455 456 /** 457 * ResultSet を DBTableModelに割り当てます。 458 * 459 * 毎回,検索毎に,DBTableModel にコピーするイメージです。 460 * ResulSet 以外のオブジェクトから,DBTableModelを作成する場合は, 461 * このメソッドをオーバーライドします。 462 * 463 * このメソッドは, execute からのみ,呼び出されます。 464 * それ以外からは呼出し出来ません。 465 * 466 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 467 * @og.rev 3.3.3.3 (2003/08/06) カラムのラベル名を、大文字に変換する。 468 * @og.rev 3.8.5.0 (2006/03/02) CLOB カラムかどうかを判定しCLOBの場合は、Clob オブジェクトから文字列を取り出します。 469 * @og.rev 3.8.8.8 (2007/05/11) ROWID対応(小数点対応 "0.3" が ".3" と表示される対策) 470 * @og.rev 4.0.0.0 (2006/01/31) CLOB カラムかどうかを判定しCLOBの場合は、ストリームから値を取り出します。 471 * @og.rev 5.3.6.0 (2011/06/01) DBTableModel作成処理をDBTableModelUtilに移動&集計機能対応 472 * @og.rev 6.3.6.1 (2015/08/28) close(),realClose() 廃止。Queryはキャッシュしません。 473 * 474 * @param resultSet ResultSetオブジェクト 475 */ 476 protected void createTableModel( final ResultSet resultSet ) { 477 try { 478 if( config == null ) { 479 table = DBTableModelUtil.makeDBTable( resultSet, getSkipRowCount(), maxRowCount, resource ); 480 } 481 else { 482 table = DBTableModelUtil.makeEditDBTable( resultSet, getSkipRowCount(), maxRowCount, resource, config ); 483 } 484 485 setExecuteCount( table.getRowCount() ); 486 } 487 catch( final SQLException ex ) { 488 final String errMsg = "テーブルモデルを作成できませんでした。"; 489 throw new HybsSystemException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並び順変更 490 } 491 } 492 493 /** 494 * ConnectionFactory.connection( String ); を利用して,Connection 495 * オブジェクトを取り出します。 496 * 497 * コネクションプールが一杯の場合は、即エラーになります。 498 * 499 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 500 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 501 * @og.rev 5.1.9.0 (2010/08/01) transaction 属性追加。 502 * @og.rev 6.3.6.1 (2015/08/28) transaction 属性廃止。内部のConnectionを返します。 503 * 504 * @return コネクション 505 */ 506 protected Connection getConnection() { 507 return connection; 508 } 509 510 /** 511 * この接続が、PreparedStatement#getParameterMetaData() を使用するかどうかを判定します。 512 * 513 * ConnectionFactory#useParameterMetaData(String) の結果を返します。(postgreSQL対応) 514 * 515 * ※ 暫定処理です。もっと、良い方法を考える必要があります。 516 * 517 * @og.rev 5.3.8.0 (2011/08/01) 新規追加 518 * @og.rev 6.3.6.1 (2015/08/28) 内部変数にconnIDが無くなったため、直接所得することになりました。 519 * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。 520 * 521 * @return 使用する場合:true / その他:false 522 * @see org.opengion.fukurou.db.ConnectionFactory#useParameterMetaData(String) 523 */ 524 protected boolean useParameterMetaData() { 525 // return ConnectionFactory.useParameterMetaData( connID ); 526 try { 527 return "PostgreSQL".equalsIgnoreCase( connection.getMetaData().getDatabaseProductName() ); 528 } 529 catch( final Throwable th ) { 530 System.err.println( ThrowUtil.ogStackTrace( th ) ); // 6.4.2.0 (2016/01/29) 531 } 532 return false ; 533 } 534 535 ////////////////////////////////////////////////////////////////////////// 536 // 537 // Object クラスのオーバーライド部分 538 // 539 ////////////////////////////////////////////////////////////////////////// 540 541 /** 542 * オブジェクトの識別子として,最後のクエリーを返します。 543 * 544 * @return 最後のクエリー 545 * @og.rtnNotNull 546 */ 547 @Override 548 public String toString() { 549 return "LastQuery :[" + getStatement() + "] "; 550 } 551}