    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 * ●形式：&lt;og:tableUpdate command="…" names="…" queryType="JDBCTableUpdate" &gt;
    058 *             {&#064;SQL}
    059 *         &lt;/og:tableUpdate&gt;
    060 *
    061 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    062 *
    063 * ●Tag定義：
    064 *   &lt;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】条件判定するカラムＩＤを指定します(初期値: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 *   &gt;   ... Body ...
    091 *   &lt;/og:tableUpdate&gt;
    092 *
    093 * ●使用例
    094 *    ・QUERYを他のJSPから渡す場合
    095 *    【copy.jsp】
    096 *        &lt;og:hidden name=&quot;SQL&quot; &gt;
    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 *               &#39;1&#39;,&#39;{&#064;USER.YMDH}&#39;,&#39;{&#064;USER.YMDH}&#39;,&#39;{&#064;USER.ID}&#39;,&#39;{&#064;USER.ID}&#39;,&#39;{&#064;GUI.KEY}&#39;)
    103 *        &lt;/og:value&gt;
    104 *
    105 *    【entry.jsp】
    106 *        &lt;og:tableUpdate
    107 *            command   = &quot;{&#064;command}&quot;
    108 *            queryType = &quot;JDBCTableUpdate&quot;
    109 *        {&#064;SQL}
    110 *        &lt;/og:tableUpdate&gt;
    111 *
    112 *    ・tableUpdateParamを使用する場合
    113 *    【entry.jsp】
    114 *        &lt;og:tableUpdate
    115 *            command   = &quot;{&#064;command}&quot;
    116 *            queryType = &quot;JDBCTableUpdate&quot;
    117 *            sqlType   = &quot;{&#064;sqlType}&quot;        // tableUpdateParam の sqlType と一致
    118 *        &gt;
    119 *            &lt;og:tableUpdateParam
    120 *                sqlType     = &quot;{&#064;sqlType}"       // INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE
    121 *                table       = &quot;{&#064;TABLE_NAME}"    // 処理対象のテーブル名
    122 *                names       = &quot;{&#064;names}"         // 処理対象のカラム名
    123 *                omitNames   = &quot;{&#064;omitNames}"     // 処理対象外のカラム名
    124 *                where       = &quot;{&#064;where}"         // 処理対象を特定するキー
    125 *                constKeys   = &quot;{&#064;constKeys}"     // 処理カラム名の中の固定情報カラム名
    126 *                constVals   = &quot;{&#064;constVals}"     // 処理カラム名の中の固定情報設定値
    127 *            /&gt;
    128 *        &lt;/og:tableUpdate&gt;
    129 *
    130 *    ・処理の可否を指定する場合
    131 *    【entry.jsp】
    132 *        &lt;og:tableUpdate
    133 *            command   = &quot;{&#064;command}&quot;
    134 *            queryType = &quot;JDBCTableUpdate&quot;
    135 *            conditionKey  ="…"      : 条件判定するカラムＩＤを指定(初期値は columnId )
    136 *            conditionList ="…"      : 条件判定する値のリストを、"|"で区切って登録(初期値は、無条件)
    137 *        {&#064;SQL}
    138 *        &lt;/og:tableUpdate&gt;
    139 *
    140 *    ・JDBCTableUpdate のまま、sqlType="MERGE" を指定する場合。
    141 *      一つのtableUpdateParamで、両方(UPDATE,INSERT)の処理を実行します。
    142 *    【entry.jsp】
    143 *        &lt;og:tableUpdate
    144 *            command   = "{&#064;command}"
    145 *            queryType = "JDBCTableUpdate"
    146 *            &lt;og:tableUpdateParam
    147 *                sqlType     = "MERGE"                // INSERT or UPDATE
    148 *                table       = "{&#064;TABLE_NAME}"    // 処理対象のテーブル名
    149 *                names       = "{&#064;names}"         // 処理対象のカラム名
    150 *                omitNames   = "{&#064;omitNames}"     // 処理対象外のカラム名
    151 *                where       = "{&#064;where}"         // 処理対象を特定するキー（INSERT時には使われず、UPDAET時に使われる。）
    152 *                constKeys   = "{&#064;constKeys}"     // 処理カラム名の中の固定情報カラム名
    153 *                constVals   = "{&#064;constVals}"     // 処理カラム名の中の固定情報設定値
    154 *            /&gt;
    155 *        &lt;/og:tableUpdate&gt;
    156 *
    157 * @og.rev 3.8.8.0 (2007/12/22) 新規作成
    158 * @og.group ＤＢ登録
    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    ;                       // 条件判定するカラムＩＤを指定(初期値は 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;         // 条件判定するカラムＩＤを指定(初期値は 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         * なにも選ばれていない場合は、サイズ０の配列を返します。
    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       (選ばれていない場合は、サイズ０の配列を返す)
    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】条件判定するカラムＩＤを指定します(初期値:null)。
    519         *
    520         * @og.tag
    521         * 指定のカラムＩＤの値と、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         * 指定することで、複数条件(ＯＲ結合)での比較を行い、リストにカラム値が
    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のパラメータに
    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}