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.taglib; 017 018// import java.util.Locale; 019import java.util.Set; 020import java.sql.Connection; 021import java.sql.ResultSet; 022import java.sql.Statement; 023import java.sql.PreparedStatement; 024import java.sql.SQLException; 025import java.sql.ParameterMetaData; 026 027import org.opengion.hayabusa.common.HybsSystem; 028import org.opengion.hayabusa.common.HybsSystemException; 029import org.opengion.hayabusa.resource.GUIInfo; 030import org.opengion.fukurou.system.Closer ; 031import org.opengion.fukurou.util.ErrorMessage; 032import org.opengion.fukurou.util.StringUtil; 033import org.opengion.fukurou.util.ArraySet; 034import org.opengion.fukurou.db.Transaction; 035import org.opengion.fukurou.db.QueryMaker; 036import org.opengion.fukurou.db.ResultSetValue; 037import org.opengion.fukurou.db.ConnectionFactory; 038 039import static org.opengion.fukurou.util.StringUtil.nval; 040 041/** 042 * データベースのデータコピー/移動/更新/削除を行うタグです。 043 * 044 * <pre> 045 * 検索結果のデータを、action に応じた方法で、処理します。 046 * SELECT文は、BODY部に記述することも可能です。 047 * BODY にSELECT文を記述しない場合は、names と、table から、SELECT文を作成します。 048 * names2 は、INSERTやUPDATE の カラム名で、SELECT文の先頭から順に適用します。 049 * WHERE条件は、SELECT結果を利用できますが、必ず、names2 のカラムか、そうでないならば、 050 * それ以降に記述してください。 051 * 052 * このタグは、DBTableModel を経由せず、直接、接続元から接続先へデータ処理を行います。 053 * 接続元の1レコード単位に、接続先に対して、処理を実行します。 054 * よって、大量データ処理が可能ですが、まとめ処理を行っていない分、時間が掛かります。 055 * 056 * 用途としては、WORKテーブルへのデータコピーや、BKUPテーブルへのコピーが考えられ 057 * ますが、それらは、select insert などの直接的な処理のほうが良いです。 058 * ここでは、別ユーザーや、別インスタンス、または、別データベース(ORACLEから、MySQLへ)など、 059 * dbid違いのテーブルへのデータ処理用途を、想定しています。 060 * なので、複雑な処理や、PL/SQL等のデータベース独自処理は行えません。 061 * SELECT文は、直接記述できるため、データベース固有の関数や、構文を記載可能ですが、 062 * INSERT,UPDATE,DELETE 文は、基本的に共通構文であり、WHERE条件等も、一般的は範囲に 063 * とどめてください。 064 * 065 * SELECTカラムとINSERTカラムが異なる場合は、name 指定と、name2 指定のカラムが対応します。 066 * 追加、更新先のカラム名に変更して置いてください。 067 * BODY部にSELECT文を記述した場合は、カラム順が、name 順となり、name2 と対応されます。 068 * constKeys,constVals も、更新先のカラム名で指定します。 069 * 処理の途中でエラー(例えば、ユニークキー制約等)になった場合は、stopError属性の 070 * 値に応じて処理を継続するかどうかを決定します。 071 * stopError="true" が初期値なので、エラー時点で、処理を中断します。 072 * 073 * action="INSERT" 074 * SELECT結果を、table2 に、INSERT します。where2,whereNames2 は使用しません。 075 * name2 を使用しない場合は、name と同じカラム配列で、INSERT します。 076 * stopError="false"(エラー時も継続する) とした場合、SELECT結果は、最後まで 077 * INSERTを試みます。 078 * 079 * action="UPDATE" 080 * SELECT結果を、table2 に、where2,whereNames2 に基づいて UPDATE します。 081 * SELECTには、更新で使用する where条件となるカラムを含める必要があります。 082 * 更新するカラムは、name2 で指定することになります。 083 * 更新対象が存在しなかった場合は、エラーとは判定していません。 084 * 085 * action="DELETE" 086 * SELECT結果を、table2 に、where2,whereNames2 に基づいて table2 のデータを 削除 します。 087 * SELECTには、削除で使用する where条件となるカラムを含める必要があります。 088 * 削除対象が存在しなかった場合は、エラーとは判定していません。 089 * 090 * action="MERGE" 091 * SELECT結果を、table2 に、where2,whereNames2 に基づいて UPDATE/INSERT します。 092 * SELECTには、更新で使用する where条件となるカラムを含める必要があります。 093 * 更新するカラムは、name2 で指定することになります。 094 * 更新対象が存在しなかった場合は、INSERT になります。 095 * (つまり、更新を一度試みて、更新件数が、0件の場合に、INSERTします。) 096 * INSERTするカラムは、SELECTしたすべてのカラムが対象になります。 097 * 098 * useDelete="true" を指定すると、検索元のデータを削除します。 099 * INSERT 時に指定すれば、MOVE と同じ効果になります。 100 * stopError="false" (エラー時でも処理を継続する)にした場合、検索元のデータ削除は、 101 * エラー行については、実行されません。ただし、UPDATE,DELETE 等で、対象データが 102 * 存在しない場合は、エラーと判断しないため、検索元のデータを削除します。 103 * 104 * SystemData の USE_SQL_INJECTION_CHECK が true か、quotCheck 属性が true の場合は、 105 * SQLインジェクション対策用のシングルクォートチェックを行います。リクエスト引数に 106 * シングルクォート(')が含まれると、エラーになります。 107 * 108 * DBLastSql はセットされません。 109 * つまり、このタグでSELECTされたデータを、ファイル出力することはできません。 110 * 111 * 実行後にリクエストパラメータに以下の値がセットされます。 112 * DB.COUNT : 検索結果の件数 113 * DB.UPCOUNT : 追加/更新/削除結果の件数 114 * DB.ERR_CODE : 検索結果のエラーコード(複数合った場合は、最後のエラーコード) 115 * 116 * ※ このタグは、Transaction タグの対象です。 117 * 118 * @og.formSample 119 * ●形式: 120 * ・<og:dbCopy action="INSERT" table="TEST_A" table2="TEST_B" /> 121 * TEST_A のすべてカラム、データを、TEST_B にコピーします。 122 * 123 * ・<og:dbCopy action="UPDATE" names2="A2,B2" table2="TEST_B" where2="C2=[c1]" > 124 * select a1,b1,c1 from TEST_A where d1='XXX' order by a1 125 * </og:dbCopy> 126 * TEST_A のa1→A2 , b1→B2 カラムに、WHERE条件 TEST_B.C2 が、TEST_A.c1 に一致するデータのみ 更新します。 127 * 128 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します) 129 * 130 * ●Tag定義: 131 * <og:dbCopy 132 * action 【TAG】実行方法[INSERT/UPDATE/DELETE/MERGE]を指定します(初期値:INSERT)。 133 * useDelete 【TAG】(jdbcオプション)検索した元のデータを削除するかどうか[true:削除する/false:なにもしない]を指定します(初期値:false)。 134 * maxRowCount 【TAG】(通常は使いません)データの最大読み込み件数を指定します (初期値:0:[無制限]) 135 * stopZero 【TAG】検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する]) 136 * dbid 【TAG】検索する対象のDB接続IDを指定します(初期値:null) 137 * table 【TAG】検索する対象のテーブル名を指定します 138 * names 【TAG】検索する対象のカラム名をCSV形式で複数指定します(初期値:*) 139 * where 【TAG】検索する対象を特定するキー条件(where句)を指定します 140 * orderBy 【TAG】検索する対象の検索順(order by句)を指定します 141 * dbid2 【TAG】登録する対象のDB接続IDを指定します(初期値:null) 142 * table2 【TAG】登録する対象のテーブル名を指定します 143 * names2 【TAG】登録する対象のカラム名をCSV形式で複数指定します 144 * omitNames2 【TAG】登録する対象外のカラム名をCSV形式で複数指定します 145 * where2 【TAG】登録する対象を特定するキー条件(where句)を指定します 146 * whereNames2 【TAG】登録する対象を特定するキー条件(where句)をCSV形式で複数指定します 147 * constKeys2 【TAG】設定値を固定値と置き換える対象となるカラム名をCSV形式で複数指定します 148 * constVals2 【TAG】設定値を固定値と置き換える対象となる設定値をCSV形式で複数指定します 149 * quotCheck 【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_SQL_INJECTION_CHECK[=true]) 150 * stopError 【TAG】登録処理エラーの時に処理を中止するかどうか[true/false]を設定します(初期値:true) 151 * dispError 【TAG】エラー時にメッセージを表示するか[true/false]を設定します。通常はstopErrorと併用(初期値:true) 152 * fetchSize 【TAG】(通常は使いません)データのフェッチサイズを指定します(初期値:DB_FETCH_SIZE[={@og.value SystemData#DB_FETCH_SIZE}]) 153 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 154 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 155 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 156 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 157 * caseIf 【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない) 158 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 159 * > ... Body ... 160 * </og:dbCopy> 161 * 162 * ●使用例 163 * ・<og:dbCopy action="INSERT" names2="A2,B2,C2" table2="TEST_B" > 164 * select a1,b1,c1 from TEST_A where d1='XXX' order by a1 165 * </og:dbCopy> 166 * TEST_A のa1→A2 , b1→B2 , c1→C2 カラムに、追加します。 167 * 168 * ・<og:dbCopy action="INSERT" names="a1,b1,c1" table="TEST_A" names2="A2,B2,C2" table2="TEST_B" /> 169 * TEST_A のa1→A2 , b1→B2 , c1→C2 カラムに、追加します。 (先の例と同じ処理) 170 * 171 * ・<og:dbCopy action="INSERT" table="TEST_A" where="d1='1'" dbid="LOCAL" dbid2="OTHER" > 172 * 接続先:LOCAL の TEST_A の 全カラムのd1='1' のレコードを、接続先:OTHER のTEST_A に追加します。 173 * 接続先違い(ユーザー、やデータベース違い)へのINSERTです。 174 * table2 を指定しない場合は、table と同じとみなされます。 175 * 176 * ・<og:dbCopy action="INSERT" table="TEST_A" where="d1='1'" dbid="LOCAL" dbid2="OTHER" stopError="false" useDelete="true" > 177 * 接続先:LOCAL の TEST_A の 全カラムのd1='1' のレコードを、接続先:OTHER のTEST_A に移動します。 178 * 接続先違い(ユーザー、やデータベース違い)への移動です。 179 * 先のINSERT が成功したレコードは削除され、最後まで処理が行われます。 180 * INSERTが失敗(つまり、接続先:OTHER にすでに、ユニークレコードが存在する場合など)時の、検索元のレコードは 181 * 削除されません。 182 * 183 * ・<og:dbCopy action="MERGE" table="TEST_A" where="d1='1'" dbid="LOCAL" names2="a1,b1,c1" dbid2="OTHER" where="ukey=[ukey]" stopError="false" useDelete="true" > 184 * 接続先:LOCAL の TEST_A の 全カラムのd1='1' のレコードを、接続先:OTHER のTEST_A に移動します。 185 * 接続先:OTHER に、移動先.ukey=[移動元ukey] のデータがあれば、name2="a1,b1,c1" カラムだけ、UPDATE を行い、 186 * 更新件数が、0件の場合は、検索したすべてのカラムで、INSERT を行います。 187 * </pre> 188 * 189 * @og.group DB検索 190 * @og.group DB登録 191 * 192 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 193 * 194 * @version 6.8.6.0 (2018/01/19) 195 * @author Kazuhiko Hasegawa 196 * @since JDK8.0, 197 */ 198public class DBCopyTag extends CommonTagSupport { 199 /** このプログラムのVERSION文字列を設定します。 {@value} */ 200 private static final String VERSION = "6.9.1.0 (2018/02/26)" ; 201 private static final long serialVersionUID = 691020180226L ; 202 203 /** action 引数に渡す事の出来る アクションコマンド 追加する {@value} */ 204 public static final String ACT_INSERT = "INSERT" ; 205 /** action 引数に渡す事の出来る アクションコマンド 更新する {@value} */ 206 public static final String ACT_UPDATE = "UPDATE" ; 207 /** action 引数に渡す事の出来る アクションコマンド 削除する {@value} */ 208 public static final String ACT_DELETE = "DELETE" ; 209 /** action 引数に渡す事の出来る アクションコマンド マージする {@value} */ 210 public static final String ACT_MERGE = "MERGE" ; 211 212 /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ {@value} */ 213 private static final int DB_FETCH_SIZE = HybsSystem.sysInt( "DB_FETCH_SIZE" ) ; 214 215// /** fetchSize の初期値 {@value} */ 216// public static final int FETCH_SIZE = 1000 ; // 6.9.3.0 (2018/03/26) 初期値を100→1000 に変更 217 218 private static final Set<String> ACTION_SET = new ArraySet<>( ACT_INSERT , ACT_UPDATE , ACT_DELETE , ACT_MERGE ); 219 220 /** エラーメッセージID {@value} */ 221 private static final String ERR_MSG_ID = HybsSystem.ERR_MSG_KEY; 222 223 private QueryMaker query = new QueryMaker(); // 検索元のSELECTのSQL文 224 private QueryMaker query2 = new QueryMaker(); // 登録先のSQL文 225 226 private ErrorMessage errMessage ; 227 228 private String action = ACT_INSERT; // 実行方法[INSERT/UPDATE/DELETE/MERGE]を指定します(初期値:INSERT)。 229 private boolean useDelete ; // (jdbcオプション)検索した元のデータを削除するかどうか[true:削除する/false:なにもしない]を指定します(初期値:false)。 230 private int maxRowCount ; // データの最大読み込み件数を指定します (初期値:0:[無制限]) 231// private String displayMsg = HybsSystem.sys( "VIEW_DISPLAY_MSG" ); // 検索結果を画面上に表示するメッセージリソースIDを指定します (初期値:VIEW_DISPLAY_MSG[=]) 232// private String overflowMsg = "MSG0007"; // 検索結果が、制限行数を超えましたので、残りはカットされました。 233// private String notfoundMsg = "MSG0077"; // 対象データはありませんでした。 234 private boolean stopZero ; // 検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する]) 235 private String dbid ; // 検索する対象のDB接続IDを指定します(初期値:null) 236 private String dbid2 ; // 登録する対象のDB接続IDを指定します(初期値:null) 237 private boolean quotCheck = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" ); // シングルクォート(') 存在チェックを実施するかどうか[true/false] 238 // (初期値:USE_SQL_INJECTION_CHECK[=true]) 239 private boolean stopError = true; // 登録処理エラーの時に処理を中止するかどうか[true/false]を設定します(初期値:true) 240 private boolean dispError = true; // エラー時にメッセージを表示するか[true/false]を設定します。通常はstopErrorと併用(初期値:true) 241 private int fetchSize = DB_FETCH_SIZE ; // フェッチする行数(初期値を100→SystemData.DB_FETCH_SIZE に変更) 242 243// private int errCode = ErrorMessage.OK; // 処理結果のエラーコード(複数合った場合は、最後のエラーコード) 244 private long dyStart ; // 実行時間測定用のDIV要素を出力します。 245 246 private String selSQL ; // 検索元のSELECT文を一時保管する変数。 247 private int selCnt ; // DB.COUNT : 検索結果の件数 248 private int upCnt ; // DB.UPCOUNT : 追加/更新/削除結果の件数 249 250 /** 251 * デフォルトコンストラクター 252 * 253 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 254 */ 255 public DBCopyTag() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 256 257 /** 258 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 259 * 260 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 261 * 262 * @return 後続処理の指示 263 */ 264 @Override 265 public int doStartTag() { 266 useXssCheck( false ); // XSS対策:チェックしません。 267 268 if( useTag() && check( action, ACTION_SET ) ) { 269 dyStart = System.currentTimeMillis(); 270 // removeSessionAttribute( ERR_MSG_ID ); // 先に、エラーデータを削除しておきます。 271 272 errMessage = new ErrorMessage( "DBCopyTag Database Error!" ); 273 setSessionAttribute( ERR_MSG_ID,errMessage ); 274 275 query.setQueryType( "SELECT" ); // 検索元のQUERYタイプ(SELECT固定) 276 query2.setQueryType( action ); // 登録先のQUERYタイプ(actionと同じ) 277 278 // 初期設定 279 // table2 を指定しない場合は、table と同じテーブルが使用されます。 280 if( StringUtil.isNull( query2.getTable() ) ) { query2.setTable( query.getTable() ); } 281 282 // names2を、指定しない場合は、names または、SELECT文のすべてのカラムが、同一名として処理されます。 283 if( StringUtil.isNull( query2.getNames() ) ) { query2.setNames( query.getNames() ); } 284 285 return EVAL_BODY_BUFFERED ; // Body を評価する。( extends BodyTagSupport 時) 286 } 287 return SKIP_BODY ; // Body を評価しない 288 } 289 290 /** 291 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。 292 * 293 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 294 * 295 * @return 後続処理の指示(SKIP_BODY) 296 */ 297 @Override 298 public int doAfterBody() { 299 debugPrint(); 300 301 useQuotCheck( quotCheck ); // SQLインジェクション対策 302 303 selSQL = getBodyString(); 304 305 return SKIP_BODY ; 306 } 307 308 /** 309 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 310 * 311 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 312 * 313 * @return 後続処理の指示 314 */ 315 @Override 316 public int doEndTag() { 317 debugPrint(); 318 319 if( useTag() && check( action, ACTION_SET ) ) { 320 if( StringUtil.isNull( selSQL ) ) { 321 selSQL = query.getSelectSQL(); // この段階で、SELECT文の整合性チェックが行われます。 322 } 323 324 execute(); // 実際の処理 325 326 final int errCode = errMessage.getKekka(); 327 328 setRequestAttribute( "DB.COUNT" , String.valueOf( selCnt ) ); // DB.COUNT : 検索結果の件数 329 setRequestAttribute( "DB.UPCOUNT" , String.valueOf( upCnt ) ); // DB.UPCOUNT : 追加/更新/削除結果の件数 330 setRequestAttribute( "DB.ERR_CODE" , String.valueOf( errCode ) ); // 検索結果のエラーコード(複数合った場合は、最後のエラーコード) 331 332 final int rtnCode ; 333 if( errCode >= ErrorMessage.NG ) { // 異常 334 setSessionAttribute( ERR_MSG_ID,errMessage ); 335 336 final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() ); 337 // エラーメッセージをリクエスト変数で持つようにしておく 338 setRequestAttribute( "DB.ERR_MSG", err ); 339 340 if( dispError ) { jspPrint( err ); } // dispErrorで表示をコントロール 341 342 rtnCode = stopError ? SKIP_PAGE : EVAL_PAGE ; 343 } 344 else { 345 removeSessionAttribute( ERR_MSG_ID ); // 問題なければ、エラーデータを削除しておきます。 346 // 件数0件かつ stopZero = true 347 rtnCode = selCnt == 0 && stopZero ? SKIP_PAGE : EVAL_PAGE ; 348 } 349 return rtnCode ; 350 } 351 352 return EVAL_PAGE ; 353 } 354 355 /** 356 * タグリブオブジェクトをリリースします。 357 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 358 * 359 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 360 * @og.rev 6.9.1.0 (2018/02/26) displayMsg,overflowMsg,notfoundMsg は未使用のため、削除 361 * 362 */ 363 @Override 364 protected void release2() { 365 super.release2(); 366 errMessage = null; 367 selSQL = null; // 検索SELECT文 368 action = ACT_INSERT; // 実行方法[INSERT/UPDATE/DELETE/MERGE]を指定します(初期値:INSERT)。 369 useDelete = false; // (jdbcオプション)検索した元のデータを削除するかどうか[true:削除する/false:なにもしない]を指定します(初期値:false)。 370 maxRowCount = 0; // データの最大読み込み件数を指定します (初期値:0:[無制限]) 371// displayMsg = HybsSystem.sys( "VIEW_DISPLAY_MSG" ); // 検索結果を画面上に表示するメッセージリソースIDを指定します (初期値:VIEW_DISPLAY_MSG[=]) 372// overflowMsg = "MSG0007"; // 検索結果が、制限行数を超えましたので、残りはカットされました。 373// notfoundMsg = "MSG0077"; // 対象データはありませんでした。 374 stopZero = false; // 検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する]) 375 dbid = null; // 検索する対象のDB接続IDを指定します(初期値:null) 376 query = new QueryMaker(); // 検索元のSELECTのSQL文 377 dbid2 = null; // 登録する対象のDB接続IDを指定します(初期値:null) 378 query2 = new QueryMaker(); // 登録先のSQL文 379 quotCheck = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" ); 380 stopError = true; // 登録処理エラーの時に処理を中止するかどうか[true/false]を設定します(初期値:true) 381 dispError = true; // エラー時にメッセージを表示するか[true/false]を設定します。通常はstopErrorと併用(初期値:true) 382 fetchSize = DB_FETCH_SIZE ; // フェッチする行数(初期値を100→SystemData.DB_FETCH_SIZE に変更) 383// errCode = ErrorMessage.OK; // 処理結果のエラーコード(複数合った場合は、最後のエラーコード) 384 dyStart = 0L; // 実行時間測定用のDIV要素を出力します。 385 selCnt = 0; // DB.COUNT : 検索結果の件数 386 upCnt = 0; // DB.UPCOUNT : 追加/更新/削除結果の件数 387 } 388 389 /** 390 * Query を実行します。 391 * 392 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 393 * @og.rev 6.9.0.2 (2018/02/13) カラム名が、"*" の場合の対応 394 */ 395 private void execute() { 396 Statement stmt = null; // 検索に使用するステートメント 397 ResultSetValue rsv = null; // 検索に使用 398 PreparedStatement pstmt2 = null; // INSERT/UPDATE/DELETE に使用するステートメント 399 PreparedStatement pstmt3 = null; // MERGE時に使用する INSERT 用ステートメント 400 ParameterMetaData pMeta2 = null; 401 ParameterMetaData pMeta3 = null; 402 403 final boolean useParamMetaData = ConnectionFactory.useParameterMetaData( dbid2 ); 404 405 String sql2 = null ; 406 String sql3 = null ; 407 final StringBuilder val2Buf = new StringBuilder( BUFFER_MIDDLE ); // 6.9.0.2 (2018/02/13) デバッグ情報用 408 final StringBuilder val3Buf = new StringBuilder( BUFFER_MIDDLE ); // 6.9.0.2 (2018/02/13) デバッグ情報用 409 410 // Transaction でAutoCloseableを使用したtry-with-resources構築に対応。 411 try( final Transaction tran = getTransaction() ) { 412 // errMessage = new ErrorMessage( "DBCopyTag Database Error!" ); 413 414 final Connection conn = tran.getConnection( dbid ); 415 stmt = conn.createStatement(); 416 if( fetchSize > 0 ) { stmt.setFetchSize( fetchSize ); } 417 final ResultSet resSer = stmt.executeQuery( selSQL ); // useDelete で使うため 418 rsv = new ResultSetValue( resSer ); // ResultSet を引数に、インスタンス作成 419 420 // names2を、指定しない場合は、names または、SELECT文のすべてのカラムが、同一名として処理されます。 421 // 6.9.0.2 (2018/02/13) カラム名が、"*" の場合の対応 422// if( StringUtil.isNull( query2.getNames() ) ) { // nullチェックは、すでに終了している。 423 if( "*".equals( query2.getNames() ) ) { 424 final String names2 = String.join( "," , rsv.getNames() ); // SELECT文の名前配列から、CSV文字列を作成 425 query2.setNames( names2 ); 426 } 427 428 switch( action ) { 429 case "INSERT" : sql2 = query2.getInsertSQL(); break; 430 case "UPDATE" : sql2 = query2.getUpdateSQL(); break; 431 case "DELETE" : sql2 = query2.getDeleteSQL(); break; 432 case "MERGE" : sql2 = query2.getUpdateSQL(); 433 sql3 = query2.getInsertSQL(); break; 434 default : break; 435 } 436 437 if( StringUtil.isNull( sql2 ) ) { 438 final String errMsg = "更新用QUERY が作成できませんでした。 " 439 + " action=[" + action + "]" 440 + " query2=[" + sql2 + "]" ; 441 errMessage.addMessage( errMsg ); 442 throw new HybsSystemException( errMsg ); 443 } 444 445 final String[] prmNms2 = query2.getParamNames( false ); // 登録QUERYの、変数設定されているカラム名配列。 446 final int[] clmNos2 = rsv.getColumnNos( prmNms2,true ); // 変数設定カラムのカラム番号。無ければ、Exception 447 448 int[] clmNos3 = null; // MERGE のときの変数設定カラム 449 450 final boolean useMerge = "MERGE".equals( action ); 451 452 final Connection conn2 = tran.getConnection( dbid2 ); 453 pstmt2 = conn2.prepareStatement( sql2 ); 454 pMeta2 = useParamMetaData ? pstmt2.getParameterMetaData() : null ; 455 if( useMerge ) { 456 final Connection conn3 = tran.getConnection( dbid2 ); 457 pstmt3 = conn3.prepareStatement( sql3 ); 458 pMeta3 = useParamMetaData ? pstmt3.getParameterMetaData() : null ; 459 460 final String[] prmNms3 = query2.getParamNames( true ); // MERGE のときの INSERT時なので、true を指定。 461 clmNos3 = rsv.getColumnNos( prmNms3,true ); // 変数設定カラムのカラム番号。無ければ、Exception 462 } 463 464 while( rsv.next() ) { 465 try { 466 selCnt++; // 検索件数の加算 467 val2Buf.setLength(0); // 初期化 468 final String[] vals = rsv.getValues(); 469 for( int no=0; no<clmNos2.length; no++ ) { 470 final int cno = clmNos2[no]; // 変数設定カラムに該当するアドレス。 471 final String val = vals[cno]; 472 val2Buf.append( val ).append( ',' ); // valueのCSV形式 473 if( useParamMetaData ) { 474 final int type = pMeta2.getParameterType( no+1 ); 475 if( val == null || val.isEmpty() ) { 476 pstmt2.setNull( no+1, type ); 477 } 478 else { 479 pstmt2.setObject( no+1,val,type ); 480 } 481 } 482 else { 483 // pstmt2.setString( no+1,vals[cno] ); 484 pstmt2.setObject( no+1,val ); 485 } 486 } 487 488 int cnt = pstmt2.executeUpdate(); // 更新件数 489 if( useMerge && cnt == 0 ) { // マージアクションで、更新が0件の場合は、INSERTを行う。 490 val3Buf.setLength(0); // 初期化 491 for( int no=0; no<clmNos3.length; no++ ) { 492 final int cno = clmNos3[no]; // 変数設定カラムに該当するアドレス。 493 final String val = vals[cno]; 494 val3Buf.append( val ).append( ',' ); // valueのCSV形式 495 if( useParamMetaData ) { 496 final int type = pMeta3.getParameterType( no+1 ); 497 if( val == null || val.isEmpty() ) { 498 pstmt3.setNull( no+1, type ); 499 } 500 else { 501 pstmt3.setObject( no+1,val,type ); 502 } 503 } 504 else { 505 // pstmt3.setString( no+1,vals[cno] ); 506 pstmt3.setObject( no+1,val ); 507 } 508 } 509 cnt = pstmt3.executeUpdate(); // 追加件数 510 } 511 512 upCnt += cnt; // 更新件数の加算 513 if( useDelete ) { resSer.deleteRow(); } // 途中でエラーになった場合は、ResultSet の削除は行いません。 514 } 515 catch( final SQLException ex ) { 516 errMessage.addMessage( selCnt,ErrorMessage.NG,ex.getSQLState(),ex.getMessage() ); 517 if( stopError ) { 518 tran.rollback(); // stopError=false の場合、最後まで処理され、commit() されています。 519 throw ex; // SELECTループ中のSQLExceptionは、stopErrorの判定を行う。 520 } 521 } 522 } 523 524 tran.commit(); 525 } 526 catch( final SQLException ex ) { 527 // 6.9.0.2 (2018/02/13) デバッグ情報 528 final String errMsg = new StringBuilder( BUFFER_MIDDLE ) 529 .append( "更新処理実行中にエラーが発生しました。action=[" ) 530 .append( action ).append( ']' ).append( CR ) 531 .append( " query =[" ).append( selSQL ).append( ']' ).append( CR ) 532 .append( " query2=[" ).append( sql2 ).append( ']' ).append( CR ) 533 .append( " query3=[" ).append( sql3 ).append( ']' ).append( CR ) 534 .append( " value2=[" ).append( val2Buf ).append( ']' ).append( CR ) 535 .append( " value3=[" ).append( val3Buf ).append( ']' ).append( CR ) 536 .toString(); 537 538// final String errMsg = "更新処理実行中にエラーが発生しました。action=[" + action + "]" + CR 539// + " query=[" + selSQL + "]" + CR 540// + " query2=[" + sql2 + "]"; 541 542 errMessage.addMessage( ex ); 543 // errMessage.addMessage( errMsg ); 544 errMessage.addMessage( -1,ErrorMessage.NG,ex.getSQLState(),errMsg ); 545 throw new HybsSystemException( errMsg,ex ); 546 } 547 finally { 548 rsv.close(); 549 Closer.stmtClose( stmt ); 550 Closer.stmtClose( pstmt2 ); 551 Closer.stmtClose( pstmt3 ); 552 } 553 554 // 変数の関係で、こちらにもって来ました(データアクセス件数登録) 555 final long dyTime = System.currentTimeMillis()-dyStart; 556 final GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY ); 557 if( guiInfo != null ) { 558 guiInfo.addReadCount( selCnt,dyTime,selSQL ); 559 guiInfo.addWriteCount( upCnt,dyTime,sql2 ); 560 } 561 } 562 563 /** 564 * 【TAG】実行方法を指定します[INSERT/UPDATE/DELETE/MERGE] (初期値:INSERT)。 565 * 566 * @og.tag 567 * 指定できるアクションは、追加(INSERT)、更新(UPDATE)、削除(DELETE)、マージ(MERGE)です。 568 * マージ以外は、お馴染みのSQL処理です。 569 * マージは、条件にしたがって、UPDATEを行い、更新件数が、0件の場合に、INSERTを行う、複合処理です。 570 * 初期値は、INSERT です。 571 * 572 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 573 * 574 * @param action アクション [INSERT/UPDATE/DELETE/MERGE] 575 */ 576 public void setAction( final String action ) { 577 this.action = nval( getRequestParameter( action ),this.action ); 578 } 579 580 /** 581 * 【TAG】(jdbcオプション)検索した元のデータを削除するかどうか[true:削除する/false:なにもしない]を指定します(初期値:false)。 582 * 583 * @og.tag 584 * アクションで指定した処理とともに、検索元のデータを削除するかどうかを指定します。 585 * 例えば、action="INSERT" で、useDelete="true" を指定すると、 ResultSet#deleteRow() を実行して、 586 * 検索元のデータを削除し、更新先にINSERT するため見かけ上、データ移動することになります。 587 * stopError="false" (エラー時でも処理を継続する)にした場合、検索元のデータ削除は、 588 * エラー行については、実行されません。ただし、UPDATE,DELETE 等で、対象データが 589 * 存在しない場合は、エラーと判断しないため、検索元のデータを削除します。 590 * 初期値は、false です。 591 * ※ ResultSet#deleteRow() をサポートしない場合もあるため、仕様の有無は、対象DBをご確認ください。 592 * 593 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 594 * 595 * @param useDel 検索した元のデータを削除するかどうか 596 */ 597 public void setUseDelete( final String useDel ) { 598 useDelete = nval( getRequestParameter( useDel ),useDelete ); 599 } 600 601 /** 602 * 【TAG】(通常は使いません)データの最大読み込み件数を指定します(初期値:0:[無制限])。 603 * 604 * @og.tag 605 * 検索処理の最大件数を指定します。 606 * このタグでは、検索都度、更新するため、メモリ等の負荷は、DBTableModel を使用する 607 * 通常の検索より少なくてすみます。 608 * 初期値は、0(無制限=実際は、Integer.MAX_VALUE)です。 609 * 610 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 611 * 612 * @param count 最大件数 613 */ 614 public void setMaxRowCount( final String count ) { 615 maxRowCount = nval( getRequestParameter( count ),maxRowCount ); 616 if( maxRowCount == 0 ) { maxRowCount = Integer.MAX_VALUE ; } 617 } 618 619// /** 620// * 【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します 621// * (初期値:VIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}])。 622// * 623// * @og.tag 624// * ここでは、検索結果の件数や登録された件数をまず出力し、 625// * その次に、ここで指定したメッセージをリソースから取得して表示します。 626// * 件数を表示させる場合は、displayMsg = "MSG0033"[ 件検索しました] をセットしてください。 627// * 表示させたくない場合は, displayMsg = "" をセットしてください。 628// * (初期値:システム定数のVIEW_DISPLAY_MSG[={@og.value SystemData#VIEW_DISPLAY_MSG}])。 629// * 630// * @og.rev 6.8.6.0 (2018/01/19) 新規作成 631// * @og.rev 6.9.1.0 (2018/02/26) displayMsg,overflowMsg,notfoundMsg は未使用のため、削除 632// * 633// * @param id 表示メッセージID 634// * @see org.opengion.hayabusa.common.SystemData#VIEW_DISPLAY_MSG 635// */ 636// public void setDisplayMsg( final String id ) { 637// final String ids = getRequestParameter( id ); 638// if( ids != null ) { displayMsg = ids; } 639// } 640 641// /** 642// * 【TAG】検索データが最大検索数をオーバーした場合に表示するメッセージリソースIDを指定します 643// * (初期値:MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました])。 644// * 645// * @og.tag 646// * 検索結果が、maxRowCount で設定された値より多い場合、何らかのデータは検索されず 647// * 切り捨てられたことになります。 648// * ここでは、displayMsg を表示した後、必要に応じて、このメッセージを表示します。 649// * 表示させたくない場合は, overflowMsg = "" をセットしてください。 650// * 初期値は、MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました]です。 651// * 652// * @og.rev 6.8.6.0 (2018/01/19) 新規作成 653// * @og.rev 6.9.1.0 (2018/02/26) displayMsg,overflowMsg,notfoundMsg は未使用のため、削除 654// * 655// * @param id オーバー時メッセージID 656// */ 657// public void setOverflowMsg( final String id ) { 658// final String ids = getRequestParameter( id ); 659// if( ids != null ) { overflowMsg = ids; } 660// } 661 662// /** 663// * 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])。 664// * 665// * @og.tag 666// * ここでは、検索結果がゼロ件の場合のみ、特別なメッセージを表示させます。 667// * 従来は、displayMsg と兼用で、『0 件検索しました』という表示でしたが、 668// * displayMsg の初期表示は、OFF になりましたので、ゼロ件の場合のみ別に表示させます。 669// * 表示させたくない場合は, notfoundMsg = "" をセットしてください。 670// * 初期値は、MSG0077[対象データはありませんでした]です。 671// * 672// * @og.rev 6.8.6.0 (2018/01/19) 新規作成 673// * @og.rev 6.9.1.0 (2018/02/26) displayMsg,overflowMsg,notfoundMsg は未使用のため、削除 674// * 675// * @param id ゼロ件メッセージID 676// */ 677// public void setNotfoundMsg( final String id ) { 678// final String ids = getRequestParameter( id ); 679// if( ids != null ) { notfoundMsg = ids; } 680// } 681 682 /** 683 * 【TAG】検索結果が0件のとき処理を停止するかどうか[true/false]を指定します(初期値:false[続行する])。 684 * 685 * @og.tag 686 * 初期値は、false(続行する)です。 687 * 688 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 689 * 690 * @param cmd 0件時停止可否 [true:処理を中止する/false:続行する] 691 */ 692 public void setStopZero( final String cmd ) { 693 stopZero = nval( getRequestParameter( cmd ),stopZero ); 694 } 695 696 /** 697 * 【TAG】(通常は使いません)検索する対象のDB接続IDを指定します(初期値:null)。 698 * 699 * @og.tag 700 * 検索側のSELECT文を実行するDB接続IDを指定します。 701 * これは、システムリソースで、DEFAULT_DB_URL 等で指定している データベース接続先 702 * 情報に、XX_DB_URL を定義することで、 dbid="XX" とすると、この 接続先を使用して 703 * データベースにアクセスできます。 704 * 初期値は、Default(=null) です。 705 * 706 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 707 * 708 * @param id データベース接続ID 709 */ 710 public void setDbid( final String id ) { 711 dbid = nval( getRequestParameter( id ),dbid ); 712 } 713 714 /** 715 * 【TAG】検索する対象のテーブル名を指定します(初期値:null)。 716 * 717 * @og.tag 718 * 検索は、この table名を検索するか、BODYに記述された SQL 文を実行します。 719 * 単独検索の場合(JOIN等を行わない場合)に、使用します。 720 * 721 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 722 * 723 * @param table テーブル名 724 */ 725 public void setTable( final String table ) { 726 query.setTable( getRequestParameter( table ) ); 727 } 728 729 /** 730 * 【TAG】検索する対象のカラム名をCSV形式で複数指定します(初期値:*)。 731 * 732 * @og.tag 733 * 複数ある場合は、CSV形式で渡します。 734 * BODYにSELECT文を記述した場合は、names 属性は不要です。 735 * 記述した場合は、SELECTしたカラムから、names属性に指定されたカラムだけを 736 * SELECT対象にします。 737 * 検索元の names と、登録先の、names2 が、対応関係になります。 738 * 初期値は、指定のカラムすべて(*)です。 739 * 740 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 741 * 742 * @param names 引数の名称 (CSV形式) 743 */ 744 public void setNames( final String names ) { 745 query.setNames( getRequestParameter( names ) ); 746 } 747 748 /** 749 * 【TAG】検索する対象を特定するキー条件(where句)を指定します。 750 * 751 * @og.tag 752 * 検索するSELECT文のwhere 句を指定します。通常の WHERE 句の書き方と同じで、 753 * {@XXXX} などが使えます。 754 * 複雑な場合は、BODY に記述してください。where タグや、andタグ等を使って、 755 * 通常のquery タグで指定する方法を、そのまま使います。 756 * 757 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 758 * 759 * @param where 検索条件 (where句) 760 */ 761 public void setWhere( final String where ) { 762 query.setWhere( getRequestParameter( where ) ); 763 } 764 765 /** 766 * 【TAG】検索する対象の検索順(order by句)を指定します。 767 * 768 * @og.tag 769 * 検索するSELECT文のorder by 句を指定します。通常の order by 句の書き方と同じで、 770 * {@XXXX} などが使えます。 771 * 772 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 773 * 774 * @param orderBy 検索条件 (order By句) 775 */ 776 public void setOrderBy( final String orderBy ) { 777 query.setOrderBy( getRequestParameter( orderBy ) ); 778 } 779 780 /** 781 * 【TAG】登録する対象のDB接続IDを指定します(初期値:null)。 782 * 783 * @og.tag 784 * 登録側のINSERT/UPDATE/DELETE文を実行するDB接続IDを指定します。 785 * これは、システムリソースで、DEFAULT_DB_URL 等で指定している データベース接続先 786 * 情報に、XX_DB_URL を定義することで、 dbid="XX" とすると、この 接続先を使用して 787 * データベースにアクセスできます。 788 * 初期値は、Default(=null) です。 789 * 790 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 791 * 792 * @param id データベース接続ID 793 */ 794 public void setDbid2( final String id ) { 795 dbid2 = nval( getRequestParameter( id ),dbid2 ); 796 } 797 798 /** 799 * 【TAG】登録する対象のテーブル名を指定します(初期値:null)。 800 * 801 * @og.tag 802 * 登録は、この table名を使用します。 803 * table2 を指定しない場合は、table と同じテーブルが使用されます。 804 * その場合は、必ず、table が指定されます。 805 * 806 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 807 * 808 * @param table テーブル名 809 */ 810 public void setTable2( final String table ) { 811 query2.setTable( getRequestParameter( table) ); 812 } 813 814 /** 815 * 【TAG】登録する対象のカラム名をCSV形式で複数指定します(初期値:null)。 816 * 817 * @og.tag 818 * 登録する対象のカラム名は、検索したカラム名の順番に割り当てられます。 819 * 例えば、names 属性に、a1,b1,c1 と指定した場合、names2 に、A2,B2,C2 と指定すれば、 820 * 順番に、a1→A2 , b1→B2 , c1→C2 に割り当てられます。 821 * BODY にSELECT文を記述した場合も、names2 を指定すれば、指定のカラムの順番に割り当てます。 822 * これは、SELECT 側と、INSERT/UPDATE 側のカラム名が異なる場合に、検索側に、別名(as 別名)を 823 * 指定する必要がありません。 824 * 指定しない場合(初期値)は、names または、SELECT文のすべてのカラムが、同一名として処理されます。 825 * 826 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 827 * 828 * @param names 引数の名称 (CSV形式) 829 */ 830 public void setNames2( final String names ) { 831 query2.setNames( getRequestParameter( names) ); 832 } 833 834 /** 835 * 【TAG】登録対象外のカラム名をCSV形式で複数指定します(初期値:null)。 836 * 837 * @og.tag 838 * names2 の逆で、登録対象から省くカラム名を指定します。 839 * table 指定や、select * from で、カラム名を大量に指定したい場合、names2 で 840 * 指定するより、除外するカラム名を指定するほうが、少なく(判りやすく)なる 841 * 場合があります。 842 * 843 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 844 * 845 * @param omitNames 登録対象外のカラム列 (CSV形式) 846 */ 847 public void setOmitNames2( final String omitNames ) { 848 query2.setOmitNames( getRequestParameter( omitNames ) ); 849 } 850 851 /** 852 * 【TAG】登録する対象を特定するキー条件(where句)を指定します。 853 * 854 * @og.tag 855 * 登録するUPDATE/DELETE文のwhere 句を指定します。通常の{@XXXX} のほかに、 856 * [検索カラム名] も使用できます。これは、検索側の where 属性と異なります。 857 * ただし、複雑な where 条件は使えませんので、できるだけ、検索側で調整して置いてください。 858 * action="UPDATE/DELETE/MERGE" でのみ有効です。 859 * 860 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 861 * 862 * @param where 検索条件 (where句) 863 */ 864 public void setWhere2( final String where ) { 865 query2.setWhere( getRequestParameter( where) ); 866 } 867 868 /** 869 * 【TAG】登録する対象を特定するキー条件(where句)をCSV形式で複数指定します。 870 * 871 * @og.tag 872 * 生成するUPDATEのwhere 句を指定する方法として、複数のカラム名をCSV指定し、内部で 873 * KEY=[KEY] 文字列を作成します。 874 * ここでは、カラム名は、データベースのカラム名と同じで、かつ、検索側にも 875 * 同じカラムのデータが存在していること、という条件付きとします。 876 * また、where 条件との併用を行いますが、こちらの条件が先に使用され、where 条件は、 877 * and を付けて、文字列結合されます。 878 * 例: CLM,SYSTEM_ID,KBSAKU ⇒ CLM=[CLM] and SYSTEM_ID=[SYSTEM_ID] and KBSAKU=[KBSAKU] 879 * 880 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 881 * 882 * @param names 登録条件カラム (where句)作成のためのカラム名(CSV形式) 883 */ 884 public void setWhereNames2( final String names ) { 885 query2.setWhereNames( getRequestParameter( names) ); 886 } 887 888 /** 889 * 【TAG】設定値を固定値と置き換える対象となるカラム名をCSV形式で複数指定します。 890 * 891 * @og.tag 892 * names 属性のカラムや table 属性より、INSERT/UPDATE文を作成する場合 893 * 外部から指定した固定値を指定するための、カラム名をCSV形式(CSV)で複数指定します。 894 * 895 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 896 * 897 * @param keys 固定値カラム (CSV形式) 898 * @see #setConstVals2( String ) 899 */ 900 public void setConstKeys2( final String keys ) { 901 query2.setConstKeys( getRequestParameter( keys ) ); 902 } 903 904 /** 905 * 【TAG】設定値を固定値と置き換える対象となる設定値をCSV形式で複数指定します。 906 * 907 * @og.tag 908 * names 属性のカラムや table 属性より、INSERT/UPDATE文を作成する場合 909 * 外部から指定した固定値を指定するための、カラム名に対応する設定値をCSV形式(CSV)で 910 * 複数指定します。ここで指定する設定値は、constKeys2 属性と対応させます。 911 * 912 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 913 * 914 * @param vals 設定値(CSV形式) 915 * @see #setConstKeys2( String ) 916 */ 917 public void setConstVals2( final String vals ) { 918 query2.setConstVals( getRequestParameter( vals ) ); 919 } 920 921 /** 922 * 【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します 923 * (初期値:USE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])。 924 * 925 * @og.tag 926 * SQLインジェクション対策の一つとして、暫定的ではありますが、SQLのパラメータに 927 * 渡す文字列にシングルクォート(') を許さない設定にすれば、ある程度は防止できます。 928 * 数字タイプの引数には、 or 5=5 などのシングルクォートを使用しないコードを埋めても、 929 * 数字チェックで検出可能です。文字タイプの場合は、必ず (')をはずして、 930 * ' or 'A' like 'A のような形式になる為、(')チェックだけでも有効です。 931 * (') が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。 932 * 初期値は、SystemData#USE_SQL_INJECTION_CHECK です。 933 * 934 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 935 * 936 * @param flag クォートチェック [true:する/それ以外:しない] 937 */ 938 public void setQuotCheck( final String flag ) { 939 quotCheck = nval( getRequestParameter( flag ),quotCheck ); 940 } 941 942 /** 943 * 【TAG】登録処理エラーの時に処理を中止するかどうか[true/false]を設定します(初期値:true)。 944 * 945 * @og.tag 946 * false(中止しない)に設定する場合、後続処理では、{@DB.ERR_CODE}の値により、 947 * 異常/正常判断を行いますが、処理は、継続されます。 948 * ちなみに、更新/削除処理で、対象データが存在しない場合(0件更新や、0件削除)は、エラーでは 949 * ありません。 950 * 初期値は、true(中止する)です。 951 * 952 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 953 * 954 * @param flag エラー時処理中止 [true:中止する/false:中止しない] 955 */ 956 public void setStopError( final String flag ) { 957 stopError = nval( getRequestParameter( flag ),stopError ); 958 } 959 960 /** 961 * 【TAG】エラー時にメッセージを表示するか[true/false]を設定します。通常はstopErrorと併用(初期値:true)。 962 * 963 * @og.tag 964 * false(表示しない)に設定する場合、後続処理では、{@DB.ERR_MSG}の値により、 965 * 本来表示されるはずだったメッセージを取得可能です。 966 * stopErrorと併用して、JSON形式でエラーを返す場合等に利用します。 967 * 初期値は、true(表示する)です。 968 * ※false指定の場合は件数等も表示されなくなります。 969 * 970 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 971 * 972 * @param flag [true:表示する/false:表示しない] 973 */ 974 public void setDispError( final String flag ) { 975 dispError = nval( getRequestParameter( flag ),dispError ); 976 } 977 978 /** 979 * 【TAG】(通常は使いません)データのフェッチサイズを指定します 980 * (初期値:DB_FETCH_SIZE[={@og.value SystemData#DB_FETCH_SIZE}])。 981 * 982 * @og.tag 983 * より多くの行が必要なときに、データベースから取り出す必要がある行数に 984 * ついてのヒントを JDBC ドライバに提供します。 985 * 指定された行数は、この Statement を使って作成された結果セットにだけ影響します。 986 * 指定された値が 0 の場合、ヒントは無視されます。 987 * (初期値:システム定数のDB_FETCH_SIZE[={@og.value SystemData#DB_FETCH_SIZE}])。 988 * 989 * @param size フェッチ行数 990 */ 991 public void setFetchSize( final String size ) { 992 fetchSize = nval( getRequestParameter( size ),fetchSize ); 993 } 994 995 /** 996 * このオブジェクトの文字列表現を返します。 997 * 基本的にデバッグ目的に使用します。 998 * 999 * @og.rev 6.8.6.0 (2018/01/19) 新規作成 1000 * 1001 * @return このクラスの文字列表現 1002 */ 1003 @Override 1004 public String toString() { 1005 return selSQL == null ? "" 1006 : selSQL.replaceAll( "[\\\t]+"," " ).replaceAll( "[\\s]+\\\n","\\\n" ) ; 1007 // 連続するTABをスペースに 連続する空白文字と改行を改行のみに 1008 } 1009}