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
018import java.util.ArrayList;
019import java.util.List;
020import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
021import java.util.regex.Pattern;                                                                 // 7.0.1.8 (2019/01/28)
022
023import org.opengion.fukurou.util.ErrorMessage;
024import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
025import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
026import org.opengion.hayabusa.common.HybsSystem;
027import org.opengion.hayabusa.common.HybsSystemException;
028import org.opengion.hayabusa.db.DBTableModel;
029import org.opengion.hayabusa.db.Query;
030import org.opengion.hayabusa.resource.GUIInfo;
031
032import static org.opengion.fukurou.util.StringUtil.nval;
033import static org.opengion.fukurou.system.HybsConst.BR;                 // 6.1.0.0 (2014/12/26) refactoring
034
035/**
036 * SQL文を直接指定して、データベースに追加/更新/削除を行います(queryType="JDBCTableUpdate")。
037 *
038 * 存在チェックを行う場合は、tableExist タグと併用してください。
039 * 複雑な処理が必要な場合は、従来より使用しています、PLSQLをCALLする、
040 * plsqlUpdateタグを使用してください。
041 * また、tableUpdateParam タグを使用する事で、テーブル名とsqlTypeの指定で動的に
042 * SQL文を自動生成できます。これにより、追加、更新、削除やテーブルに関して、
043 * 単一のJSP画面ですべて対応できるようになります。
044 *
045 * 7.2.9.3 (2020/11/06)
046 *   queryType="JDBCTableMerge" と、"JDBCTableUpdate" を相互運用します。
047 *   tableUpdateParam タグのsqlType="MERGE" を指定しておくと、
048 *   UPDATE文とINSERT文を両方とも作成して、有れば更新なければ追加処理を行います。
049 *   その場合、queryTypeを、JDBCTableMerge に変更します。
050 *   sqlType が従来の"INSERT"や"UPDATE" の場合は、queryTypeを、JDBCTableUpdate
051 *   に変更します。
052 *   この変換は、"JDBCTableMerge" と、"JDBCTableUpdate" を相互運用します。
053 *
054 * ※ このタグは、Transaction タグの対象です。
055 *
056 * @og.formSample
057 * ●形式:<og:tableUpdate command="…" names="…" queryType="JDBCTableUpdate" >
058 *             {@SQL}
059 *         </og:tableUpdate>
060 *
061 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
062 *
063 * ●Tag定義:
064 *   <og:tableUpdate
065 *       queryType          【TAG】Query を発行する為のクラスID(JDBCTableUpdate,JDBCTableMerge)を指定します({@og.doc03Link queryType 初期値:JDBCTableUpdate})
066 *       sqlType            【TAG】BODY部に書かれている Param の SQLタイプを指定します(INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE,無指定)
067 *       command            【TAG】コマンド (NEW,RENEW)をセットします(PlsqlUpdateTag,UpdateTag の場合は、ENTRY)
068 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)
069 *       displayMsg         【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します (初期値:VIEW_DISPLAY_MSG[=])
070 *       resourceType       【特殊】クリアするリソースの種類[GEA03/GEA04/GEA08]を指定します
071 *       conditionKey       【TAG】条件判定するカラムIDを指定します(初期値:null)
072 *       conditionList      【TAG】条件判定する値のリストを、"|"で区切って登録します(初期値:無条件) 7.0.1.8 (2019/01/28) 正規表現に変更
073 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
074 *       dbid               【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します
075 *       selectedAll        【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
076 *       selectedOne        【TAG】データを1件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
077 *       changeOnly         【TAG】変更があったデータのみを処理するかどうか[true/false]を指定します(初期値:false) 7.4.2.0 (2021/04/30)
078 *       commitTableModel   【特殊】SQL実行後に結果をDBTableModelに反映させるかどうか[true/false]を指定します(初期値:true)
079 *       followCdkh         【TAG】DBTableModelの改廃Cに従って処理を行うかを指定します
080 *       quotCheck          【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します(初期値:false)
081 *       useTimeView        【TAG】処理時間を表示する TimeView を表示するかどうかを指定します
082 *                                                                              (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
083 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
084 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
085 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
086 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
087 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
088 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
089 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
090 *   >   ... Body ...
091 *   </og:tableUpdate>
092 *
093 * ●使用例
094 *    ・QUERYを他のJSPから渡す場合
095 *    【copy.jsp】
096 *        <og:hidden name="SQL" >
097 *          INSERT INTO GE41
098 *               (CLM,NAME_JA,LABEL_NAME,KBSAKU,SYSTEM_ID,LANG,
099 *               FGJ,DYSET,DYUPD,USRSET,USRUPD,PGUPD)
100 *          VALUES
101 *               ([CLM],[NAME_JA],[LABEL_NAME],[KBSAKU],[SYSTEM_ID],[LANG],
102 *               '1','{@USER.YMDH}','{@USER.YMDH}','{@USER.ID}','{@USER.ID}','{@GUI.KEY}')
103 *        </og:value>
104 *
105 *    【entry.jsp】
106 *        <og:tableUpdate
107 *            command   = "{@command}"
108 *            queryType = "JDBCTableUpdate"
109 *        {@SQL}
110 *        </og:tableUpdate>
111 *
112 *    ・tableUpdateParamを使用する場合
113 *    【entry.jsp】
114 *        <og:tableUpdate
115 *            command   = "{@command}"
116 *            queryType = "JDBCTableUpdate"
117 *            sqlType   = "{@sqlType}"        // tableUpdateParam の sqlType と一致
118 *        >
119 *            <og:tableUpdateParam
120 *                sqlType     = "{@sqlType}"       // INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE
121 *                table       = "{@TABLE_NAME}"    // 処理対象のテーブル名
122 *                names       = "{@names}"         // 処理対象のカラム名
123 *                omitNames   = "{@omitNames}"     // 処理対象外のカラム名
124 *                where       = "{@where}"         // 処理対象を特定するキー
125 *                constKeys   = "{@constKeys}"     // 処理カラム名の中の固定情報カラム名
126 *                constVals   = "{@constVals}"     // 処理カラム名の中の固定情報設定値
127 *            />
128 *        </og:tableUpdate>
129 *
130 *    ・処理の可否を指定する場合
131 *    【entry.jsp】
132 *        <og:tableUpdate
133 *            command   = "{@command}"
134 *            queryType = "JDBCTableUpdate"
135 *            conditionKey  ="…"      : 条件判定するカラムIDを指定(初期値は columnId )
136 *            conditionList ="…"      : 条件判定する値のリストを、"|"で区切って登録(初期値は、無条件)
137 *        {@SQL}
138 *        </og:tableUpdate>
139 *
140 *    ・JDBCTableUpdate のまま、sqlType="MERGE" を指定する場合。
141 *      一つのtableUpdateParamで、両方(UPDATE,INSERT)の処理を実行します。
142 *    【entry.jsp】
143 *        <og:tableUpdate
144 *            command   = "{@command}"
145 *            queryType = "JDBCTableUpdate"
146 *            <og:tableUpdateParam
147 *                sqlType     = "MERGE"                // INSERT or UPDATE
148 *                table       = "{@TABLE_NAME}"    // 処理対象のテーブル名
149 *                names       = "{@names}"         // 処理対象のカラム名
150 *                omitNames   = "{@omitNames}"     // 処理対象外のカラム名
151 *                where       = "{@where}"         // 処理対象を特定するキー(INSERT時には使われず、UPDAET時に使われる。)
152 *                constKeys   = "{@constKeys}"     // 処理カラム名の中の固定情報カラム名
153 *                constVals   = "{@constVals}"     // 処理カラム名の中の固定情報設定値
154 *            />
155 *        </og:tableUpdate>
156 *
157 * @og.rev 3.8.8.0 (2007/12/22) 新規作成
158 * @og.group DB登録
159 *
160 * @version  4.0
161 * @author   Kazuhiko Hasegawa
162 * @since    JDK5.0,
163 */
164public class TableUpdateTag extends QueryTag {
165        /** このプログラムのVERSION文字列を設定します。   {@value} */
166        private static final String VERSION = "7.4.2.0 (2021/04/30)" ;
167        private static final long serialVersionUID = 742020210430L ;
168
169        /** command 引数に渡す事の出来る コマンド  登録{@value} */
170        public static final String CMD_ENTRY  = "ENTRY" ;
171        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
172        private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_ENTRY );
173
174        // 処理を行う、リソースの種類を指定します。(GEA03,GEA04,GEA08 のどれか)
175        private String  sqlType                 ;                       // INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE
176        private String  resourceType    ;
177        private int             resTypeColNo    = -1;
178        private String  conditionKey    ;                       // 条件判定するカラムIDを指定(初期値は columnId )
179        private String  conditionList   ;                       // 条件判定する値のリストを、"|"で区切って登録(初期値は、無条件) 7.0.1.8 (2019/01/28) 正規表現に変更
180        private boolean selectedAll             ;
181        private boolean selectedOne             ;                       // 7.4.2.0 (2021/04/30) 変更があったデータのみを処理するかどうか[true/false]を指定します(初期値:false)
182        private boolean changeOnly              ;                       // 7.4.2.0 (2021/04/30) 変更があったデータのみを処理するかどうか[true/false]を指定します(初期値:false)
183        private boolean commitTableModel= true;         // 4.0.2.0 (2007/12/25)
184        private boolean followCdkh              ;                       // 4.3.2.0 (2008/09/09).
185        private boolean quotCheck               ;                       // 5.1.7.0 (2010/06/01) quotCheckを指定できるようにする。※但し、初期値はfalse固定。タイミングを見て修正要
186
187        /**
188         * デフォルトコンストラクター
189         *
190         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
191         */
192        public TableUpdateTag() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
193
194        /**
195         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
196         *
197         * @og.rev 4.0.0.0 (2007/11/14) 0件の場合でもstartQueryTransactionを通すように変更
198         * @og.rev 5.1.7.0 (2010/06/01) quotCheckを指定できるようにする。※但し、初期値はfalse固定。
199         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
200         *
201         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
202         */
203        @Override
204        public int doStartTag() {
205                if( !useTag() ) { return SKIP_BODY ; }  // 6.3.4.0 (2015/08/01)
206                dyStart = System.currentTimeMillis();
207
208                table = (DBTableModel)getObject( tableId );
209                startQueryTransaction( tableId );               // 4.0.0.0 (2007/11/14) 0件の場合でもdoEndでPAGE_SKIPしないように位置変更。
210                if( table == null || table.getRowCount() == 0 ||
211                        ! check( command, COMMAND_SET ) ) { return SKIP_BODY ; }
212                super.quotCheck = quotCheck;
213
214                return EVAL_BODY_BUFFERED ;     // Body を評価する。( extends BodyTagSupport 時)
215        }
216
217        /**
218         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
219         *
220         * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
221         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
222         * @og.rev 6.4.1.2 (2016/01/22) QueryTag.errMsgId  → QueryTag.ERR_MSG_ID  refactoring
223         * @og.rev 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
224         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
225         *
226         * @return      後続処理の指示
227         */
228        @Override
229        public int doEndTag() {
230                debugPrint();
231                if( !useTag() ) { return EVAL_PAGE ; }  // 6.3.4.0 (2015/08/01)
232
233                String label  = "";                             // 4.0.0 (2005/11/30) 検索しなかった場合。
234                if( check( command, COMMAND_SET ) ) {
235                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
236                        if( executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
237                                buf.append( executeCount )
238                                        .append( getResource().getLabel( displayMsg ) )
239                                        .append( BR );
240                        }
241
242                        // 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
243                        if( table != null && ! commitTableObject( tableId, table ) ) {
244                                if( errMessage == null ) { errMessage = new ErrorMessage( "TableUpdateTag Query Error!" ); }
245                                // ERR0041:検索処理中に割り込みの検索要求がありました。処理されません。
246                                errMessage.addMessage( 0,ErrorMessage.NG,"ERR0041" );
247                                errCode = ErrorMessage.NG;
248                        }
249
250//                      final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
251                        final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource(),useSLabel );         // 7.0.7.0 (2019/12/13)
252                        if( err != null && err.length() > 0 ) {
253                                buf.append( err );
254                                // 6.4.1.2 (2016/01/22) QueryTag.errMsgId  → QueryTag.ERR_MSG_ID  refactoring
255                                setSessionAttribute( ERR_MSG_ID,errMessage );
256                        }
257                        else {
258                                // 6.4.1.2 (2016/01/22) QueryTag.errMsgId  → QueryTag.ERR_MSG_ID  refactoring
259                                removeSessionAttribute( ERR_MSG_ID );
260                        }
261                        label = buf.toString();
262
263//                      // 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
264//                      if( table != null && ! commitTableObject( tableId, table )  ) {
265//                              // 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
266//                              jspPrint( "TableUpdateTag Query処理が割り込まれました。DBTableModel は登録しません。" );
267//                              return SKIP_PAGE ;
268//                      }
269                }
270
271                jspPrint( label );
272
273                // セキュリティチェック(データアクセス件数登録)
274                final long dyTime = System.currentTimeMillis()-dyStart;
275                final GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY );
276                if( guiInfo != null ) { guiInfo.addWriteCount( executeCount,dyTime,sql ); }
277
278                if( useTimeView ) {             // 6.3.6.0 (2015/08/16)
279                        jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );  // 3.5.6.3 (2004/07/12)
280                }
281                return errCode >= ErrorMessage.NG ? SKIP_PAGE : EVAL_PAGE ;
282        }
283
284        /**
285         * タグリブオブジェクトをリリースします。
286         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
287         *
288         * @og.rev 4.0.2.0 (2007/12/25) commitTableModel追加
289         * @og.rev 4.1.2.0 (2008/03/12) sqlType追加
290         * @og.rev 5.1.7.0 (2010/06/01) quotCheckを指定できるようにする。※但し、初期値はfalse固定。
291         * @og.rev 7.2.9.1 (2020/10/23) TableUpdateParamTag のマージ(UPDATE,INSERT)対応
292         * @og.rev 7.4.2.0 (2021/04/30) selectedOne、changeOnlyを追加します
293         */
294        @Override
295        protected void release2() {
296                super.release2();
297                sqlType                 = null;         // INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE
298                resourceType    = null;
299                resTypeColNo    = -1;
300                conditionKey    = null;         // 条件判定するカラムIDを指定(初期値は columnId )
301                conditionList   = null;         // 条件判定する値のリストを、"|"で区切って登録(初期値は、無条件) 7.0.1.8 (2019/01/28) 正規表現に変更
302                selectedAll             = false;
303                selectedOne             = false;        // 7.4.2.0 (2021/04/30)
304                changeOnly              = false;        // 7.4.2.0 (2021/04/30)
305                commitTableModel= true;         // 4.0.2.0 (2007/12/25)
306                followCdkh              = false;        // 4.3.2.0 (2008/09/09)
307                quotCheck               = false;        // 5.1.7.0 (2010/06/01)
308        }
309
310        /**
311         * Query を実行します。
312         *
313         * @og.rev 4.0.2.0 (2007/12/25) commitTableModel追加
314         * @og.rev 6.3.6.1 (2015/08/28) close(),realClose() 廃止。Queryはキャッシュしません。
315         *
316         * @param   query オブジェクト
317         */
318        @Override
319        protected void execute( final Query query ) {
320                final int[] rowNo = getParameterRows();         // 4.0.0 (2005/01/31)
321                if( rowNo.length > 0 ) {
322                        query.execute( rowNo,table );
323
324                        errCode = query.getErrorCode();
325                        errMessage = query.getErrorMessage();
326
327                        // リソースクリア処理
328                        if( resourceType != null ) {
329                                resTypeColNo = table.getColumnNo( "CLM" );              // キーは、CLM
330                        }
331
332                        // 逆順にDELETEしないと、行番号がずれてしまう。
333                        int row;
334                        for( int j=rowNo.length-1; j>=0; j-- ) {
335                                row = rowNo[j];
336                                if( resTypeColNo >= 0 ) {
337                                        clearResourceData( table.getValue( row,resTypeColNo ) );                // リソースのクリア
338                                }
339
340                                if( commitTableModel ) {        // 4.0.2.0 (2007/12/25)
341                                        if( DBTableModel.DELETE_TYPE.equals( table.getModifyType( row ) ) ) {
342                                                table.removeValue( row );
343                                        }
344                                        else {
345                                                table.resetModify( row );
346                                        }
347                                }
348                        }
349                }
350        }
351
352        /**
353         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行番号の
354         * 配列を返します。
355         * ここでは、conditionKey に値が設定されている場合は、そのカラムの値が
356         * conditionList にマッチする場合のみ対象選択行として返します。
357         * 値がセットされていない場合は、通常のCommonTagSupport#getParameterRows()
358         * が呼ばれます。
359         * なにも選ばれていない場合は、サイズ0の配列を返します。
360         *
361         * @og.rev 4.3.2.0 (2008/09/09) followCdkh属性対応
362         * @og.rev 7.0.1.8 (2019/01/28) conditionListの判定を、正規表現に変更
363         * @og.rev 7.4.2.0 (2021/04/30) selectedOne、changeOnlyを追加します
364         *
365         * @return       (選ばれていない場合は、サイズ0の配列を返す)
366         * @og.rtnNotNull
367         */
368        @Override
369        protected int[] getParameterRows() {
370                int[] rowNo ;
371                if( selectedAll ) {
372                        final int rowCnt = table.getRowCount();         // 3.5.5.7 (2004/05/10)
373                        rowNo = new int[ rowCnt ];
374                        for( int i=0; i<rowCnt; i++ ) {
375                                rowNo[i] = i;
376                        }
377                }
378                else if( selectedOne ) {                                                // 7.4.2.0 (2021/04/30)
379                        rowNo = new int[] {0};
380                }
381                else if( changeOnly ) {                                                 // 7.4.2.0 (2021/04/30)
382                        rowNo = table.getChangeRowNos();
383                }
384                else {
385                        rowNo = super.getParameterRows();                       // 4.0.0 (2005/01/31)
386                }
387
388                // 7.0.1.8 (2019/01/28) conditionListの判定を、正規表現に変更
389                if( conditionKey != null && conditionList != null ) {                   // 7.0.1.8 (2019/01/28)
390                        final int col = table.getColumnNo( conditionKey );
391                        final List<Integer> list = new ArrayList<>();
392                        final Pattern ptn = Pattern.compile( conditionList );           // 7.0.1.8 (2019/01/28)
393                        for( int i=0; i<rowNo.length; i++ ) {
394                                final String val = nval( table.getValue( rowNo[i],col ) , "" );         // 7.0.1.8 (2019/01/28)
395                                if( ptn.matcher( val ).matches() ) {
396                                        list.add( Integer.valueOf( rowNo[i] ) );
397                                }
398                        }
399
400                        // 7.4.2.0 (2021/04/30) List<Integer> を、int[] に変換します。
401                        rowNo = list.stream().mapToInt(i->i).toArray();
402
403//                      final int size = list.size();
404//                      rowNo = new int[size];
405//                      for( int i=0; i<size; i++ ) {
406//                              rowNo[i] = list.get(i).intValue();
407//                      }
408                }
409
410                // 4.3.2.0 (2008/09/09)
411                if( sqlType != null && sqlType.length() > 0 && followCdkh ) {
412                        final List<Integer> flist = new ArrayList<>();
413                        for( int i=0; i<rowNo.length; i++ ) {
414                                final String cdkh = table.getModifyType( rowNo[i] );
415                                // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
416                                if(     ( "INSERT".equals( sqlType ) || "COPY".equals(   sqlType ) )    && DBTableModel.INSERT_TYPE.equals( cdkh )
417//                                      ||      ( "UPDATE".equals( sqlType ) || "CHANGE".equals( sqlType ) )    && DBTableModel.UPDATE_TYPE.equals( cdkh )              // 7.2.9.1 (2020/10/23) CHANGE ⇒ MODIFY
418                                        ||      ( "UPDATE".equals( sqlType ) || "MODIFY".equals( sqlType ) )    && DBTableModel.UPDATE_TYPE.equals( cdkh )
419                                        ||        "DELETE".equals( sqlType )                                                                    && DBTableModel.DELETE_TYPE.equals( cdkh ) ) {
420                                                flist.add( Integer.valueOf( rowNo[i] ) );
421                                }
422                        }
423
424                        // 7.4.2.0 (2021/04/30) List<Integer> を、int[] に変換します。
425                        rowNo = flist.stream().mapToInt(i->i).toArray();
426
427//                      final int size = flist.size();
428//                      rowNo = new int[size];
429//                      for( int i=0; i<size; i++ ) {
430//                              rowNo[i] = flist.get(i).intValue();
431//                      }
432                }
433
434                return rowNo;
435        }
436
437//      /**
438//       * BODY部の TableUpdateParamTag に書かれたquery文を受け取ります。
439//       *
440//       * typeには、UPDATEかINSERTが指定され、それに応じたqueryを各変数にセットします。
441//       *
442//       * @og.rev 7.2.9.1 (2020/10/23) TableUpdateParamTag のマージ(UPDATE,INSERT)対応
443//       * @og.rev 7.2.9.3 (2020/11/06) QueryTag に移動
444//       *
445//       * @param       type    Queryタイプ(UPDATE,INSERT,その他)
446//       * @param       query   SQL文
447//       */
448//      protected void setQuery( final String type , final String query ) {
449//              sql = query;                                                                                                    // とりあえず、セットしておく
450//              sqlCnt++ ;                                                                                                              // 0の場合はBODYから、1の場合はそのまま、それ以上の場合は、マージ処理。QueryTag のprotected属性
451//
452//              if( "UPDATE".equalsIgnoreCase( type ) ) {
453//                      updQuery = query;                                                                                       // 上位の QueryTag のprotected属性
454//              }
455//              else if( "INSERT".equalsIgnoreCase( type ) ) {
456//                      insQuery = query;                                                                                       // 上位の QueryTag のprotected属性
457//              }
458//      }
459
460        /**
461         * 【TAG】Query を発行する為のクラスID(JDBCTableUpdate,JDBCTableMerge)を指定します({@og.doc03Link queryType 初期値:JDBCTableUpdate})。
462         *
463         * @og.tag
464         * 引数指定のUPDATE,INSERT,DELETE文を実行する場合の、queryType 属性を使用します。
465         * このタグでは、execute( int[] ,DBTableModel )を実行します。
466         * 代表的なクラスとして、"JDBCTableUpdate" が標準で用意されています。
467         *
468         * タグにより使用できる/出来ないがありますが、これは、org.opengion.hayabusa.db
469         * 以下の Query_**** クラスの **** を与えます。
470         * これらは、Query インターフェースを継承したサブクラスです。
471         * {@og.doc03Link queryType Query_**** クラス}
472         *
473         * @param       id Queryタイプ
474         * @see         org.opengion.hayabusa.db.Query  Queryのサブクラス
475         * @see         org.opengion.hayabusa.db.Query#execute( int[] ,DBTableModel )
476         */
477        @Override
478        public void setQueryType( final String id ) {
479                super.setQueryType( nval( id,"JDBCTableUpdate" ) );
480        }
481
482        /**
483         * resourceType が設定されたときのみ使用される、キャッシュの初期化メソッドです。
484         *
485         * @param       key     初期化を行うキー
486         */
487        private void clearResourceData( final String key ) {
488                getResource().clear( key );
489        }
490
491        /**
492         * 【特殊】クリアするリソースの種類[GEA03/GEA04/GEA08]を指定します。
493         *
494         * @og.tag
495         * 注意:この属性は、リソース関連DBのメンテナンス時にのみ、内部リソースキャッシュを
496         * クリアする目的で使用します。一般の属性としては、使用することはないため、
497         * ご注意ください。
498         * リソース関連のテーブルを更新した場合、リソースキャッシュをクリアして
499         * 置かないと、データベースの値が反映されません。
500         * 昔は、リソースの更新ごとに、全件クリアしていましたが、部分クリアが
501         * できるようになったため、部分クリアを行います。
502         * こでは、(GEA03,GEA04,GEA08) のどれかを指定してください。
503         *
504         * @param       type    クリアリソースタイプ [GEA03/GEA04/GEA08]
505         */
506        public void setResourceType( final String type ) {
507                resourceType = nval( getRequestParameter(type),resourceType );
508
509                if( resourceType != null &&
510                        "|GEA03|GEA04|GEA08|".indexOf( "|" + resourceType + "|" ) < 0 ) {
511                                final String errMsg = "resourceTypeは GEA03,GEA04,GEA08 のどれかです。"
512                                                        + "resourceType=" + type ;
513                                throw new HybsSystemException( errMsg );
514                }
515        }
516
517        /**
518         * 【TAG】条件判定するカラムIDを指定します(初期値:null)。
519         *
520         * @og.tag
521         * 指定のカラムIDの値と、conditionList の値を比較して、
522         * 存在する場合は、Query 処理を実行します。
523         * 例えば、conditionKey="CDKH" として、conditionList="A" とすれば、
524         * 改廃コードが"A"のデータで、かつ選択されたデータのみを処理します。
525         * 設定しない場合は、通常の処理と同様に、選択行のみ処理されます。
526         *
527         * @param       key 条件判定カラム
528         * @see         #setConditionList( String )
529         */
530        public void setConditionKey( final String key ) {
531                conditionKey = nval( getRequestParameter( key ),null ) ;
532        }
533
534        /**
535         * 【TAG】条件判定する値のリストを、"|"で区切って登録します(初期値:無条件)。
536         *
537         * @og.tag
538         * conditionKey とペアで指定します。ここには、カラムの設定値のリストを
539         * 指定することで、複数条件(OR結合)での比較を行い、リストにカラム値が
540         * 存在する場合のみ、Query 処理を実行します。
541         * 値が設定されている場合は、その値とマッチする必要があります。なにもセット
542         * されない場合、または、null の場合は、null データとマッチする場合のみ処理
543         * されますので、ご注意ください。
544         *
545         * @og.rev 7.0.1.8 (2019/01/28) conditionListの判定を、正規表現に変更
546         *
547         * @param       list    条件判定値 ("|"区切のリスト)
548         * @see         #setConditionKey( String )
549         */
550        public void setConditionList( final String list ) {
551//              conditionList = "|" + nval( getRequestParameter( list ),"" ) + "|" ;
552                conditionList = nval( getRequestParameter( list ),"" ) ;
553        }
554
555        /**
556         * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
557         *
558         * @og.tag
559         * 全てのデータを選択済みデータとして扱って処理します。
560         * 全件処理する場合に、(true/false)を指定します。
561         * 初期値は false です。
562         *
563         * changeOnly よりも selectedAll="true" が優先されます。 7.4.2.0 (2021/04/30)
564         *
565         * @param  all データを全件選択済み [true:全件選択済み/false:通常]
566         */
567        public void setSelectedAll( final String all ) {
568                selectedAll = nval( getRequestParameter( all ),selectedAll );
569        }
570
571        /**
572         * 【TAG】データを1件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
573         *
574         * @og.tag
575         * 先頭行の1件だけを選択済みとして処理します。
576         * まとめ処理のデータを処理する場合などに使われます。
577         * 初期値は false です。
578         *
579         * @og.rev 7.4.2.0 (2021/04/30) データを1件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
580         *
581         * @param  one 先頭行の1件だけを選択済みとして処理するかどうか [true:処理する/false:通常]
582         */
583        public void setSelectedOne( final String one ) {
584                selectedOne = nval( getRequestParameter( one ),selectedOne );
585        }
586
587        /**
588         * 【TAG】変更があったデータのみを処理するかどうか[true/false]を指定します(初期値:false)。
589         *
590         * @og.tag
591         * 変更があったデータのみを処理します。
592         * selectedAll="true" が指定された場合は、全件処理が優先されます。
593         *
594         * 通常は、チェックされた行のみか、selectedAll で全件処理しますが、空更新のデータは
595         * 登録したくないケースに、元データと異なる行のみ処理します。
596         * 初期値は false です。
597         *
598         * @og.rev 7.4.2.0 (2021/04/30) 変更があったデータのみを処理するかどうか[true/false]を指定します(初期値:false)
599         *
600         * @param  change 変更があったデータのみを処理するかどうか [true:変更分のみ/false:通常]
601         */
602        public void setChangeOnly( final String change ) {
603                changeOnly = nval( getRequestParameter( change ),changeOnly );
604        }
605
606        /**
607         * 【特殊】SQL実行後に結果をDBTableModelに反映させるかどうか[true/false]を指定します(初期値:true)。
608         *
609         * @og.tag
610         * 注意:この属性は、リソース関連DBのメンテナンス時に、複数DBへの登録を行うための、
611         * 暫定対応として定義しています。
612         * falseにした場合は、実データとDBTableModelの整合性が取れなくなるため、使用には十分注して下さい。
613         * 初期値は true です。
614         *
615         * @og.rev 4.0.2.0 (2007/12/25) 新規作成
616         *
617         * @param  commitTblMdl 反映有無 [true:反映する/false:反映しない]
618         */
619        public void setCommitTableModel( final String commitTblMdl ) {
620                commitTableModel = nval( getRequestParameter( commitTblMdl ),commitTableModel );
621        }
622
623        /**
624         * 引数の名称配列。
625         *
626         * @return      名称配列
627         */
628        protected String[] getNames() {
629                return table.getNames() ;
630        }
631
632        /**
633         * 【TAG】BODY部に書かれている Param の SQLタイプを指定します。
634         *
635         * @og.tag
636         * TableUpdateParamTag は、上位の TableUpdateTag の sqlType 属性 と同じ
637         * sqlType 属性の場合のみ、SQL文を合成・出力します。
638         * つまり、TableUpdateTag側のsqlType 属性をパラメータに、TableUpdateParamTag
639         * の sqlType 属性を固定値にすることで、どのパラメータを使用するかを
640         * 選択できる機能を実現する事が可能です。
641         *
642         * 7.2.9.3 (2020/11/06)
643         *   複数指定できるようにします。
644         *
645         * @og.rev 4.1.2.0 (2008/03/12) 新規追加
646         *
647         * @param       type SQLタイプ
648         */
649        public void setSqlType( final String type ) {
650                sqlType = nval( getRequestParameter( type ),sqlType );
651        }
652
653        /**
654         * 【TAG】DBTableModelの改廃Cに従って処理を行うかを指定します。
655         *
656         * @og.tag
657         * この属性は、sqlTypeが指定されている場合のみ有効です。
658         * sqlTypeが指定されている場合、そのsqlTypeに対応した、改廃Cが設定されている
659         * 行のみを処理します。
660         * 対応関係は、以下の通りです。
661         *  sqlType = "INSERT" or "COPY" ⇒ 改廃C='A'のみ処理
662//       *  sqlType = "UPDATE" or "CHANGE" ⇒ 改廃C='C'のみ処理
663         *  sqlType = "UPDATE" or "MODIFY" ⇒ 改廃C='C'のみ処理
664         *  sqlType = "DELETE" ⇒ 改廃C='D'のみ処理
665         *
666         * @og.rev 4.3.2.0 (2008/09/09) 新規追加
667         *
668         * @param       flag 改廃C処理 [true:行う/false:行わない]
669         */
670        public void setFollowCdkh( final String flag ) {
671                followCdkh = nval( getRequestParameter( flag ),followCdkh );
672        }
673
674        /**
675         * 【TAG】リクエスト情報の シングルクォート(') 存在チェックを実施するかどうか[true/false]を設定します(初期値:false)。
676         *
677         * @og.tag
678         * SQLインジェクション対策の一つとして、暫定的ではありますが、SQLのパラメータに
679         * 渡す文字列にシングルクォート(') を許さない設定にすれば、ある程度は防止できます。
680         * 数字タイプの引数には、 or 5=5 などのシングルクォートを使用しないコードを埋めても、
681         * 数字チェックで検出可能です。文字タイプの場合は、必ず (')をはずして、
682         * ' or 'A' like 'A のような形式になる為、(')チェックだけでも有効です。
683         * (') が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。
684         * ※(他のタグは、システムリソースのUSE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])
685         * ですが、JSPの互換性を考慮し、初期値を固定でfalseにしています)
686         *
687         * @og.rev 5.1.7.0 (2010/06/01) 新規追加
688         *
689         * @param   flag クォートチェック [true:する/それ以外:しない]
690         */
691        @Override
692        public void setQuotCheck( final String flag ) {
693                quotCheck = nval( getRequestParameter( flag ),quotCheck );
694        }
695
696        /**
697         * SQLタイプを返します。
698         *
699         * @og.rev 4.1.2.0 (2008/03/12) 新規追加
700         *
701         * @return      SQLタイプ
702         */
703        protected String getSqlType() {
704                return sqlType ;
705        }
706
707        /**
708         * このオブジェクトの文字列表現を返します。
709         * 基本的にデバッグ目的に使用します。
710         *
711         * @og.rev 4.0.2.0 (2007/12/25) resourceColumn、commitTableModel追加
712         *
713         * @return このクラスの文字列表現
714         * @og.rtnNotNull
715         */
716        @Override
717        public String toString() {
718                return ToString.title( this.getClass().getName() )
719                                .println( "VERSION"                     ,VERSION                )
720                                .println( "resourceType"        ,resourceType   )
721                                .println( "resTypeColNo"        ,resTypeColNo   )
722                                .println( "conditionKey"        ,conditionKey   )
723                                .println( "conditionList"       ,conditionList  )
724                                .println( "followCdkh"          ,followCdkh             )
725                                .println( "CMD_ENTRY"           ,CMD_ENTRY              )
726                                .println( "commitTabelModel",commitTableModel )         // 4.0.2.0 (2007/12/25)
727                                .println( "sql"                         ,sql                    )               // 4.1.2.0 (2008/03/12)
728                                .println( "Other..."    ,getAttributes().getAttribute() )
729                                .fixForm().toString()
730                        + CR
731                        + super.toString() ;
732        }
733}