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