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