    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 org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.common.HybsSystemException;
    020import org.opengion.hayabusa.db.DBColumn;
    021import org.opengion.hayabusa.db.DBTableModel;
    022import org.opengion.hayabusa.db.DBTableModelUtil;
    023import org.opengion.fukurou.system.OgBuilder ;                                  // 6.4.4.1 (2016/03/18)
    024import org.opengion.fukurou.util.StringUtil;
    025import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
    026import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
    027
    028import static org.opengion.fukurou.util.StringUtil.nval ;
    029
    030import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
    031import java.util.Map;
    032import java.util.LinkedHashMap;
    033import java.util.Locale ;
    034import java.util.List;
    035import java.util.ArrayList;
    036
    037/**
    038 * ２つの DBTableModel の 集合処理を行うタグです。
    039 *
    040 * マスタとスレーブのそれぞれの DBTableModel を取得し、マージ、差分、排他などの
    041 * データ処理を行います。結果を、指定の tableId と scope に書き出します。
    042 * マスタテーブルは、masterTableId と masterScope より取り出します。スレーブテーブルは、
    043 * slaveTableId と slaveScope より取り出します。
    044 * 取り出された DBTableModel は、マスタテーブルに対して、スレーブテーブル情報を参照する形で行われ、
    045 * 結果はマスタテーブルに上書きされる形で行われます。
    046 * 指定できるアクションは、全体集合(UNION_ALL)、和集合(UNION)、積集合(INTERSECT)、
    047 * 差集合(MINUS)、差分集合(DIFFERENCE)、列合成(UNION_CLM)、 列追加(ADD_CLM)、 グループ(GROUP)です。
    048 * 列合成と列追加、グループ以外の処理では、カラム順とカラム数は同数でなければなりません。
    049 * primaryKeys や unionClms などの指定のキー名は、マスタテーブルに存在する必要があります。
    050 * マスタテーブルと同じカラム番号でスレーブテーブルよりデータを読み出します。
    051 * (カラム名や属性は、異なってもかまいませんが、マスタテーブルに準拠します。)
    052 * また、単独(マスタテーブルのみ)で、和集合と同等の、グループ(GROUP)を使用すると、指定の
    053 * カラムでのユニーク化を行うことが可能になります。グループ処理では、先行優先とし、
    054 * ２回目に現れた情報を削除することになります。グループ が指定された場合は、
    055 * スレーブテーブルは無視されます。いずれの処理においても、集合処理を行う主キーで
    056 * 一旦グループ化されます。全体集合(UNION_ALL)で処理する場合でも、主キーがユニークで
    057 * ない場合は、マスター、スレーブの各テーブルで一旦グループ化された後で、マージされます。
    058 * (マージ後には、同一主キーを持つ行は存在します。)
    059 * 全体集合(UNION_ALL)の場合のみ、mergeKeys を指定する必要はありません。その場合は、
    060 * キーなしのため、マスターとスレーブのテーブルを単に合成するだけになります。
    061 *
    062 * 6.9.1.0 (2018/02/26)
    063 *   UNION_VAL は、スレーブテーブルの縦列を横列に割り当てるUNION_CLMの特殊版です。
    064 *   処理としては、そのまま割り当てるのではなく、スレーブテーブルの縦列の値と
    065 *   ヘッダーとして指定する、unionClms の値を比較して、下限値の最大値を割り当てます。
    066 *   つまり、ヘッダーの値と同じか、それ以下で、最も近い値を割り当てることになります。
    067 *   これは、時間的な推移を表現することになります。
    068 *     masterKeys：マスタとスレーブを関連付ける共通のキーとなるカラム
    069 *     slaveKeys ：スレーブの縦列を横列にするための、キーと値のカラム
    070 *     unionClms ：横列にするカラム名。この値とスレーブのキーと比較してセットするかどうかを決めます。
    071 *
    072 * 処理前後でのDBTableModelの件数は、以下の変数で取得することが可能です。
    073 *  処理前のマスターテーブル : {&#064;DB.MASTER_COUNT}
    074 *  処理前のスレーブテーブル : {&#064;DB.SLAVE_COUNT}
    075 *  処理後                   : {&#064;DB.COUNT}
    076 *
    077 * @og.formSample
    078 * ●形式：
    079 *       ・&lt;og:tableMerge
    080 *             action        = "UNION_ALL|UNION|INTERSECT|MINUS|DIFFERENCE|UNION_CLM|UNION_VAL|ADD_CLM|GROUP|UNION_SELROW|CDKH|TABLE_REMOVE"
    081 *             tableId       = "DEFAULT"        出力テーブルの tableId
    082 *             scope         = "session"        出力テーブルの scope
    083 *             masterTableId = "DEFAULT"        マスタテーブルの tableId
    084 *             masterScope   = "session"        マスタテーブルの scope
    085 *             slaveTableId  = "DEFAULT"        スレーブテーブルの tableId
    086 *             slaveScope    = "request"        スレーブテーブルの scope
    087 *             masterKeys    = "AA,BB,CC"       マスタテーブルの集合処理を行う主キー
    088 *             slaveKeys     = "AA,BB,CC"       スレーブテーブルの集合処理を行う主キー(null時=masterKeys)
    089 *             diffKeys      = "DD,EE"          マスタテーブルのDIFFERENCE時の差分カラム名
    090 *             unionClms     = "DD,EE"          UNION_CLM,ADD_CLM時にスレーブからマスタへ追加するカラム名
    091 *             unionLbls     = "dd,ee"          UNION_CLM,ADD_CLM時にスレーブからマスタへ追加するカラムのラベル名 6.9.1.0 (2018/02/26)
    092 *             modifyClms    = "FF,GG"          DIFFERENCE,CDKH時にスレーブからマスタへ値を更新するカラム名
    093 *             noSideEffect  = "false"          テーブルモデルに対する副作用(true:ない/false:ある)
    094 *             useDiffData   = "true"           DIFFERENCE時に差分のスレーブデータを追加するかどうか
    095 *             useCheckOnly  = "false"          マスタテーブルの選択行のデータのみを対象に処理を行うかどうか
    096 *             groupAddClms  = "FF,GG"          masterKeysで集合処理するときに、相違データをCSV連結して残すカラム名
    097 *             display       = "true"           処理概要を表示するかどうか
    098 *         /&gt;
    099 * ●body：なし
    100 *
    101 * ●Tag定義：
    102 *   &lt;og:tableMerge
    103 *       command            【TAG】コマンド (NEW,RENEW)をセットします(初期値:NEW)
    104 *       action             【TAG】アクションを指定します(UNION_ALL|UNION|INTERSECT|MINUS|DIFFERENCE|UNION_CLM|UNION_VAL|ADD_CLM|GROUP|UNION_SELROW|CDKH|TABLE_REMOVE)
    105 *       tableId            【TAG】出力先のtableIdを指定します (初期値:HybsSystem#TBL_MDL_KEY[=h_tblmdl])
    106 *       scope              【TAG】出力先のscopeを指定します(初期値:session)
    107 *       masterTableId      【TAG】マスタテーブルのtableIdを指定します (初期値:HybsSystem#TBL_MDL_KEY[=h_tblmdl])
    108 *       masterScope        【TAG】マスタテーブルのscopeを指定します(初期値:session)
    109 *       slaveTableId       【TAG】スレーブテーブルのtableIdを指定します (初期値:HybsSystem#TBL_MDL_KEY[=h_tblmdl])
    110 *       slaveScope         【TAG】スレーブテーブルのscopeを指定します(初期値:session)
    111 *       masterKeys         【TAG】マスタテーブルの集合処理を行う主キーを指定します
    112 *       slaveKeys          【TAG】スレーブテーブルの集合処理を行う主キーを指定します
    113 *       diffKeys           【TAG】マスタテーブルのDIFFERENCE時の差分カラム名を(CSV形式)指定します
    114 *       unionClms          【TAG】スレーブからマスタへ追加するカラム名をCSV形式で指定します
    115 *       unionLbls          【TAG】スレーブからマスタへ追加するラベルをCSV形式で指定します   6.9.1.0 (2018/02/26)
    116 *       nullDelClms        【TAG】指定の値がすべてnull(空文字列)の場合、レコードを削除するカラムをCSV形式で指定します
    117 *       useSlaveLoop       【TAG】scope="request" のスレーブテーブルを、ループ処理して使用します(action="TABLE_REMOVE" と、"UNION_CLM" で、利用します)
    118 *       modifyClms         【TAG】DIFFERENCE,CDKH時にスレーブからマスタへ値を更新するカラム名をCSV形式で指定します
    119 *       groupAddClms       【TAG】集合処理するときに、相違データをCSV連結して残すカラム名をCSV形式で指定します
    120 *       noSideEffect       【TAG】テーブルモデルに対する副作用の有無[true:ない/false:ある]を指定します(初期値:false:ある)
    121 *       useDiffData        【TAG】差分のスレーブデータを結果テーブルに追加するかどうかを指定します(初期値:true)
    122 *       useCheckOnly       【TAG】マスタテーブルの選択行のデータのみを対象に処理を行うかどうかを指定します(初期値:false)
    123 *       stopZero           【TAG】検索結果が０件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])
    124 *       display            【TAG】マージの結果を表示するかどうかを指定します(初期値:true)
    125 *       mainTrans          【TAG】(通常は使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:false)
    126 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
    127 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
    128 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
    129 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
    130 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
    131 *       separator          【TAG】groupAddClmsで文字列を連結する項目区切り文字をセットします(初期値:",")
    132 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    133 *   /&gt;
    134 *
    135 * ●使用例
    136 *     例１)デフォルト以外に必要な属性のみ指定するサンプル
    137 *     &lt;og:tableMerge action="UNION"
    138 *           slaveScope = "request" masterKeys = "AA,BB,CC"
    139 *     /&gt;
    140 *
    141 *         ・出力先、マスターともに初期値は、tableId="DEFAULT" scope="session" です。
    142 *           スレーブは、tableId か scope をける必要がある為、scope="request" を指定しています。
    143 *           比較するカラム名は、マスタ、スレーブ同じであれば、マスタのみ指定でかまいません。
    144 *
    145 *     例２)マスタ、スレーブともメモリに残らないように request で作成します。
    146 *     &lt;og:tableMerge action="INTERSECT"
    147 *           masterScope  = "request"
    148 *           slaveScope   = "request"
    149 *           slaveTableId = "SLAVE"
    150 *           masterKeys   = "AA,BB,CC"
    151 *     /&gt;
    152 *
    153 *         ・マスタ、スレーブともメモリに残らないように request で作成した場合は、
    154 *           どちらかの TableId を変える必要があります。
    155 *           出力先は初期値の、tableId="DEFAULT" scope="session" です。
    156 *
    157 * @og.rev 3.8.0.9 (2005/10/17) 新規追加
    158 * @og.group ＤＢ登録
    159 *
    160 * @version  0.9.0      2000/10/17
    161 * @author       Kazuhiko Hasegawa
    162 * @since    JDK5.0,
    163 */
    164public class TableMergeTag extends CommonTagSupport {
    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        /** action 引数に渡す事の出来る アクションコマンド  全体集合 {@value} */
    170        public static final String ACT_UNION_ALL        = "UNION_ALL" ;
    171        /** action 引数に渡す事の出来る アクションコマンド  和集合 {@value} */
    172        public static final String ACT_UNION            = "UNION" ;
    173        /** action 引数に渡す事の出来る アクションコマンド  積集合 {@value} */
    174        public static final String ACT_INTERSECT        = "INTERSECT" ;
    175        /** action 引数に渡す事の出来る アクションコマンド  差集合{@value} */
    176        public static final String ACT_MINUS            = "MINUS" ;
    177        /** action 引数に渡す事の出来る アクションコマンド  差分集合{@value} */
    178        public static final String ACT_DIFFERENCE       = "DIFFERENCE" ;
    179        /** action 引数に渡す事の出来る アクションコマンド  列合成{@value} */
    180        public static final String ACT_UNION_CLM        = "UNION_CLM" ;
    181        /** action 引数に渡す事の出来る アクションコマンド  列合成{@value} */
    182        public static final String ACT_UNION_VAL        = "UNION_VAL" ;                                 // 6.9.1.0 (2018/02/26)
    183        /** action 引数に渡す事の出来る アクションコマンド  列合成{@value} */
    184        public static final String ACT_ADD_CLM          = "ADD_CLM" ;
    185        /** action 引数に渡す事の出来る アクションコマンド  グループ {@value} */
    186        public static final String ACT_GROUP            = "GROUP" ;
    187        /** action 引数に渡す事の出来る アクションコマンド  グループ {@value} */
    188        public static final String ACT_UNION_SELROW     = "UNION_SELROW" ;                              // 4.3.2.0 (2008/09/11)
    189        /** action 引数に渡す事の出来る アクションコマンド  改廃コード {@value} */
    190        public static final String ACT_CDKH                     = "CDKH" ;                                              // 6.3.1.1 (2015/07/10)
    191        /** action 引数に渡す事の出来る アクションコマンド  DBTableModelの削除 {@value} */
    192        public static final String ACT_TABLE_REMOVE     = "TABLE_REMOVE" ;                              // 6.7.3.0 (2017/01/27)
    193
    194        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    195        private static final Set<String> ACTION_SET = new ArraySet<>( ACT_UNION_ALL , ACT_UNION , ACT_INTERSECT , ACT_MINUS , ACT_DIFFERENCE , ACT_UNION_CLM , ACT_UNION_VAL ,
    196                                                                                                                                  ACT_ADD_CLM , ACT_GROUP , ACT_UNION_SELROW , ACT_CDKH , ACT_TABLE_REMOVE );
    197
    198        /** command 引数に渡す事の出来る コマンド  新規 {@value} */
    199        public static final String CMD_NEW       = "NEW" ;
    200        /** command 引数に渡す事の出来る コマンド  再検索 {@value} */
    201        public static final String CMD_RENEW = "RENEW" ;
    202        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    203        private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_NEW , CMD_RENEW );
    204
    205        private String  command         = CMD_NEW;
    206
    207        private String  action          ;
    208        private String  tableId         = HybsSystem.TBL_MDL_KEY;               // 出力先の tableId
    209        private String  scope           = "session";                                    // 出力先の scope
    210
    211        private String  masterTableId   = HybsSystem.TBL_MDL_KEY;       // マスタテーブルの tableId
    212        private String  masterScope             = "session";                            // マスタテーブルの scope
    213        private String  slaveTableId    = HybsSystem.TBL_MDL_KEY;       // スレーブテーブルの tableId
    214        private String  slaveScope              = "request";                            // スレーブテーブルの scope
    215        private String  masterKeys              ;                                                       // マスタテーブルの集合処理を行う主キー
    216        private String  slaveKeys               ;                                                       // スレーブテーブルの集合処理を行う主キー(null時=masterKeys)
    217        private String  diffKeys                ;                                                       // マスタテーブルのDIFFERENCE時の差分カラム名
    218        private String  unionClms               ;                                                       // 6.7.3.0 (2017/01/27) 値がnull時にレコードを削除
    219        private String  unionLbls               ;                                                       // 6.9.1.0 (2018/02/26) 追加
    220        private String  nullDelClms             ;                                                       // UNION_CLM時にスレーブからマスタへ追加するカラム名
    221        private String  modifyClms              ;                                                       // DIFFERENCE,CDKH時にスレーブからマスタへ値を更新するカラム名
    222        private String  groupAddClms    ;                                                       // 5.1.4.0 (2010/03/01) masterKeysで集合処理するときに、相違データをCSV連結して残すカラム名
    223        private boolean noSideEffect    ;                                                       // テーブルモデルに対する副作用(true:ない/false:ある)
    224        private boolean useDiffData             = true;                                         // DIFFERENCE時に差分のスレーブデータを追加するかどうか
    225        private boolean useCheckOnly    ;                                                       // マスタテーブルの選択行のデータのみを対象に処理を行うかどうか
    226        private boolean display                 = true;
    227        private boolean isMainTrans             = true;                                         // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
    228        private String  separator               = ",";                                          // 5.3.1.0 (2011/01/01) groupAddClmnsで結合する際の区切り文字
    229        private boolean stopZero                ;                                                       // 5.7.6.2 (2014/05/16) stopZero属性追加
    230        private boolean useSlaveLoop    ;                                                       // 6.7.3.0 (2017/01/27) useSlaveLoop属性追加
    231
    232        /**
    233         * デフォルトコンストラクター
    234         *
    235         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    236         */
    237        public TableMergeTag() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    238
    239        /**
    240         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    241         *
    242         * @og.rev 4.3.2.0 (2008/09/11) UNION_SELROWアクション対応
    243         * @og.rev 4.3.3.0 (2008/10/01) 処理前後のテーブル件数を取得できるようにする
    244         * @og.rev 4.3.3.1 (2008/10/08) スレーブのnullチェック追加
    245         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
    246         * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
    247         * @og.rev 5.7.6.2 (2014/05/16) stopZero属性、DB.COUNT キーで検索件数をリクエストにセットする。
    248         * @og.rev 6.3.1.1 (2015/07/10) Map作成時に、DBTableModel のグループ化を行うかどうか指定できるようにする。
    249         * @og.rev 6.3.1.1 (2015/07/10) 改廃コードを設定する CDKH アクションを追加
    250         * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
    251         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    252         * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
    253         * @og.rev 6.7.3.0 (2017/01/27) useSlaveLoop,nullDelClms属性追加と、action="TABLE_REMOVE" の追加
    254         * @og.rev 6.9.1.0 (2018/02/26) ACT_UNION_VAL追加
    255         *
    256         * @return      後続処理の指示
    257         */
    258        @Override
    259        public int doEndTag() {
    260                debugPrint();           // 4.0.0 (2005/02/28)
    261                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
    262                if( !useTag() || ! check( command, COMMAND_SET ) ) { return EVAL_PAGE ; }
    263
    264                // 整合性チェック：アクションリストとの存在チェック
    265                if( !check( action, ACTION_SET ) ) {
    266                        final String errMsg = "指定のアクションは実行できません。アクションエラー"       + CR
    267                                                        + "action=[" + action + "] "                                                            + CR
    268                                                        + "指定可能なアクション:"
    269                                                        + String.join( ", " , ACTION_SET ) ;
    270                        throw new HybsSystemException( errMsg );
    271                }
    272
    273                // 6.7.3.0 (2017/01/27) action="TABLE_REMOVE" で、DBTableModel を無条件で、削除します。
    274                if( ACT_TABLE_REMOVE.equalsIgnoreCase( action ) ) {
    275                        super.setScope( masterScope );
    276                        removeObject( masterTableId );
    277                        return EVAL_PAGE ;
    278                }
    279
    280                // スレーブテーブルの集合処理を行う主キー(null時=masterKeys)
    281                if( slaveKeys == null ) { slaveKeys = masterKeys; }
    282
    283                super.setScope( masterScope );
    284                DBTableModel masterTable = (DBTableModel)getObject( masterTableId );
    285
    286                // 6.7.3.0 (2017/01/27) useSlaveLoop属性追加と、action="TABLE_REMOVE" の追加
    287                // 6.9.7.0 (2018/05/14) PMD These nested if statements could be combined
    288//              if( useSlaveLoop ) {
    289//                      // 初っ端はDBTableModel が存在しないはずなので、slave のテーブルを、マスターに登録しなおす。(処理は、これだけで終了)
    290//                      if( masterTable == null ) {
    291                if( useSlaveLoop && masterTable == null ) {
    292                                // 初っ端はDBTableModel が存在しないはずなので、slave のテーブルを、マスターに登録しなおす。(処理は、これだけで終了)
    293                                // slave の scope と、tableId から取り出した DBTableModel を、master に登録する。
    294                                super.setScope( slaveScope );
    295                                masterTable = (DBTableModel)getObject( slaveTableId );
    296                                if( masterTable != null && masterTable.getRowCount() > 0 ) {
    297                                        super.setScope( masterScope );
    298                                        setObject( masterTableId , masterTable );
    299                                }
    300                                return EVAL_PAGE ;
    301//                      }
    302                }
    303
    304                // 整合性チェック：マスタテーブルは必須
    305                if( masterTable == null ) {
    306                        final String errMsg = "マスタテーブルは必須です。"
    307                                                + CR
    308                                                + "action=[" + action + "] "
    309                                                + "masterTableId=[" + masterTableId + "] "
    310                                                + "masterScope=[" + masterScope + "] " ;
    311                        throw new HybsSystemException( errMsg );
    312                }
    313                if( noSideEffect ) { masterTable = cloneTable( masterTable ); }
    314                // 6.3.1.1 (2015/07/10) Map作成時に、DBTableModel のグループ化を行うかどうか指定できるようにする。
    315                // useGroup=true(行う) なので、masterTable は副作用が発生する。
    316                final Map<String,Integer> masterMap = makeKeyMap( masterTable,masterKeys,useCheckOnly,true );
    317
    318                DBTableModel slaveTable = null;
    319                Map<String,Integer> slaveMap = null;
    320
    321                // 整合性チェック：action="GROUP" と "ADD_CLM" 以外では、スレーブテーブルは必須
    322                // 6.9.1.0 (2018/02/26) ACT_UNION_VAL追加
    323                if( ! ACT_GROUP.equalsIgnoreCase( action ) && !ACT_ADD_CLM.equalsIgnoreCase( action ) ) {
    324                        super.setScope( slaveScope );
    325                        slaveTable = (DBTableModel)getObject( slaveTableId );
    326
    327                        if( slaveTable == null ) {
    328                                final String errMsg = "action=[" + action + "] 時には、スレーブテーブルが必要です。"
    329                                                        + CR
    330                                                        + "slaveTableId=[" + slaveTableId + "] "
    331                                                        + "slaveScope=[" + slaveScope + "] " ;
    332                                throw new HybsSystemException( errMsg );
    333                        }
    334                        if( noSideEffect ) { slaveTable = cloneTable( slaveTable ); }
    335                        // 6.3.1.1 (2015/07/10) Map作成時に、DBTableModel のグループ化を行うかどうか指定できるようにする。
    336                        slaveMap = makeKeyMap( slaveTable,slaveKeys,false,false );      // スレーブはuseCheckOnlyしない、グループ化しない。
    337
    338                        // その場合、マスタとスレーブが同一メモリ上のテーブル(物理的に同じ)でない事。
    339                        if( slaveTable == masterTable ) {
    340                                final String errMsg = "マスタとスレーブが同一メモリになっています。"
    341                                                        + "通常、検索結果は tableId と scope を別々に指定するか、noSideEffect=true(副作用なし)を、指定してください。"
    342                                                        + CR
    343                                                        + "action=[" + action + "] "
    344                                                        + "masterTableId=[" + masterTableId + "] "
    345                                                        + "slaveTableId=[" + slaveTableId + "] "
    346                                                        + "masterScope=[" + masterScope + "] "
    347                                                        + "slaveScope=[" + slaveScope + "] " ;
    348                                throw new HybsSystemException( errMsg );
    349                        }
    350                }
    351
    352                super.setScope( scope );
    353                useMainTrans( isMainTrans );                    // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
    354                startQueryTransaction( tableId );               // 3.6.0.8 (2004/11/19)
    355
    356                // 設定値の整合性チェック
    357                // 整合性チェック：action="UNION_ALL" と "UNION_VAL" と "GROUP"と "ADD_CLM"と "UNION_CLM" 以外では、masterKeys が必須
    358                // 6.9.1.0 (2018/02/26) ACT_UNION_VAL追加
    359                if( ! ACT_UNION_ALL.equalsIgnoreCase( action )
    360                        && !ACT_UNION_VAL.equalsIgnoreCase( action )    // 6.9.1.0 (2018/02/26)
    361                        && !ACT_UNION_SELROW.equalsIgnoreCase( action ) // 4.3.2.0 (2008/09/11)
    362                        && !ACT_GROUP.equalsIgnoreCase( action )
    363                        && !ACT_ADD_CLM.equalsIgnoreCase( action )
    364                        && !ACT_UNION_CLM.equalsIgnoreCase( action )
    365                        && masterKeys == null ) {
    366                                final String errMsg = "action=\"" + action + "\" 時には、masterKeys が必須です。"
    367                                                        + CR
    368                                                        + "masterKeys=[" + masterKeys + "] ";
    369                                throw new HybsSystemException( errMsg );
    370                }
    371
    372                // 設定値の整合性チェック
    373                // 整合性チェック：action="DIFFERENCE" では、diffKeys が必須
    374                if( ACT_DIFFERENCE.equalsIgnoreCase( action ) && diffKeys == null ) {
    375                        final String errMsg = "action=\"" + action + "\" 時には、diffKeys が必須です。"
    376                                                + CR
    377                                                + "diffKeys=[" + diffKeys + "] ";
    378                        throw new HybsSystemException( errMsg );
    379                }
    380
    381                // 設定値の整合性チェック
    382                // 整合性チェック：列合成(UNION_CLM) と 値列合成(UNION_VAL) と グループ(GROUP) と 列追加(ADD_CLM) と 積集合(INTERSECT) と 差集合(MINUS) 以外では、
    383                //                 テーブルカラム数が同じである必要がある。
    384                // 6.9.1.0 (2018/02/26) ACT_UNION_VAL追加
    385                if( ! ACT_UNION_CLM.equalsIgnoreCase( action )
    386                         && !ACT_UNION_VAL.equalsIgnoreCase( action )           // 6.9.1.0 (2018/02/26)
    387                         && !ACT_GROUP.equalsIgnoreCase( action )
    388                         && !ACT_ADD_CLM.equalsIgnoreCase( action )
    389                         && !ACT_INTERSECT.equalsIgnoreCase( action )           // 6.3.1.1 (2015/07/10) INTERSECT と MINUS を条件に追加
    390                         && !ACT_MINUS.equalsIgnoreCase( action ) ) {           // 6.3.1.1 (2015/07/10) INTERSECT と MINUS を条件に追加
    391                        final int mClmSize = masterTable.getColumnCount();
    392                        final int sClmSize = slaveTable.getColumnCount();
    393
    394                        if( mClmSize != sClmSize ) {
    395                                final String errMsg = "action=\"" + action + "\" 時には、テーブルカラム数が異なってはいけません。"
    396                                                        + CR
    397                                                        + "Master=" + mClmSize + " ,["
    398                                                        + StringUtil.array2csv( masterTable.getNames() ) + "]"
    399                                                        + CR
    400                                                        + "Slave =" + sClmSize + " ,["
    401                                                        + StringUtil.array2csv( slaveTable.getNames() ) + "]";
    402                                throw new HybsSystemException( errMsg );
    403                        }
    404                }
    405
    406                // 6.4.4.1 (2016/03/18) display == true 時の出力を後ろにします。
    407                final String MST_CNT = String.valueOf( masterTable.getRowCount() );
    408                final String SLV_CNT = slaveTable == null ? null : String.valueOf( slaveTable.getRowCount() );
    409
    410                setRequestAttribute( "DB.MASTER_COUNT"   , MST_CNT );
    411                if( SLV_CNT != null ) {
    412                        setRequestAttribute( "DB.SLAVE_COUNT", SLV_CNT );
    413                }
    414
    415                DBTableModel table = null;
    416                if( ACT_UNION_ALL.equalsIgnoreCase( action ) ) {                        // 全体集合
    417                        table = makeUnionAll( masterTable,slaveTable );
    418                }
    419                else if( ACT_UNION_SELROW.equalsIgnoreCase( action ) ) {        // 4.3.2.0 (2008/09/11) 全体集合(slave表をmaster表のチェック行から追加)
    420                        table = makeUnionSelrow( masterTable,slaveTable );
    421                }
    422                else if( ACT_UNION.equalsIgnoreCase( action ) ) {                       // 和集合
    423                        table = makeUnion( masterTable,masterMap,slaveTable,slaveMap );
    424                }
    425                else if( ACT_INTERSECT.equalsIgnoreCase( action ) ) {           // 積集合
    426                        table = makeIntersect( masterTable,masterMap,slaveMap );
    427                }
    428                else if( ACT_MINUS.equalsIgnoreCase( action ) ) {                       // 差集合
    429                        table = makeMinus( masterTable,masterMap,slaveMap );
    430                }
    431                else if( ACT_DIFFERENCE.equalsIgnoreCase( action ) ) {          // 差分集合
    432                        table = makeDifference( masterTable,masterMap,slaveTable,slaveMap );
    433                }
    434                else if( ACT_UNION_CLM.equalsIgnoreCase( action ) ) {           // 列合成
    435                        if( unionClms == null ) {
    436                                final String errMsg = "action=\"UNION_CLM\" 時には、unionClms が必須です。" ;
    437                                throw new HybsSystemException( errMsg );
    438                        }
    439
    440                        table = makeUnionClm( masterTable,slaveKeys,slaveTable,slaveMap );
    441                }
    442                // 6.9.1.0 (2018/02/26) ACT_UNION_VAL追加
    443                else if( ACT_UNION_VAL.equalsIgnoreCase( action ) ) {           // 値列合成
    444                        if( unionClms == null ) {
    445                                final String errMsg = "action=\"UNION_VAL\" 時には、unionClms が必須です。" ;
    446                                throw new HybsSystemException( errMsg );
    447                        }
    448
    449                        table = makeUnionVal( masterTable,masterKeys,slaveTable,slaveKeys );
    450                }
    451                else if( ACT_ADD_CLM.equalsIgnoreCase( action ) ) {             // 列追加
    452                        if( unionClms == null ) {
    453                                final String errMsg = "action=\"ADD_CLM\" 時には、unionClms が必須です。" ;
    454                                throw new HybsSystemException( errMsg );
    455                        }
    456
    457                        table = makeAddClm( masterTable );
    458                }
    459                else if( ACT_GROUP.equalsIgnoreCase( action ) ) {                       // グループ化は、先のレコードが残ります。
    460                        table = makeGroup( masterTable );
    461
    462                        // 6.7.3.0 (2017/01/27) nullDelClmsで、値がnull時にレコードを削除
    463                        if( nullDelClms != null && !nullDelClms.isEmpty() ) {
    464                                table = deleteRows( table,nullDelClms );
    465                        }
    466                }
    467                else if( ACT_CDKH.equalsIgnoreCase( action ) ) {                        // 6.3.1.1 (2015/07/10) CDKH
    468                        table = makeCdkh(  masterTable,masterMap,slaveTable,slaveMap );
    469                }
    470
    471                // 6.0.2.4 (2014/10/17) NP:null 値を利用している可能性があります。
    472                if( table == null ) {
    473                        final String errMsg = "テーブルデータを作成できませんでした。action=[" + action + "]" ;
    474                        throw new HybsSystemException( errMsg );
    475                }
    476
    477                // 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
    478                super.setScope( scope );
    479                if( ! commitTableObject( tableId, table ) ) {
    480                        return SKIP_PAGE ;
    481                }
    482
    483                // 5.7.6.2 (2014/05/16) マージした結果の DBTableModel のデータ件数
    484                final int rowCnt = table.getRowCount();
    485
    486                // 6.4.4.1 (2016/03/18) display == true 時の出力を後ろにします。
    487                // 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
    488                if( display ) {
    489                        final OgBuilder buf = new OgBuilder()
    490                                .append( action , "( M[" , MST_CNT , "]" )
    491                                .appendIf( SLV_CNT != null
    492                                                                , ",S["  , SLV_CNT , "]" )
    493                                .append( " ) = [" , String.valueOf( rowCnt ) , "]" );
    494
    495                        jspPrint( buf.toString() );
    496                }
    497
    498                // 5.7.6.2 (2014/05/16) 検索結果の件数を、"DB.COUNT" キーでリクエストにセットする。
    499                setRequestAttribute( "DB.COUNT" , String.valueOf( rowCnt ) );
    500
    501                // 5.7.6.2 (2014/05/16) 件数０件かつ stopZero = true
    502                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    503                return rowCnt == 0 && stopZero
    504                                        ? SKIP_PAGE
    505                                        : EVAL_PAGE ;           // ページの残りを評価する。
    506        }
    507
    508        /**
    509         * タグリブオブジェクトをリリースします。
    510         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    511         *
    512         * @og.rev 5.1.4.0 (2010/03/01) groupAddClms 追加
    513         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
    514         * @og.rev 5.3.1.0 (2011/01/01) separator追加
    515         * @og.rev 5.7.6.2 (2014/05/16) stopZero属性追加
    516         * @og.rev 6.7.3.0 (2017/01/27) useSlaveLoop,nullDelClms属性追加
    517         */
    518        @Override
    519        protected void release2() {
    520                super.release2();
    521                command                 = CMD_NEW;
    522                action                  = null;
    523                tableId                 = HybsSystem.TBL_MDL_KEY;       // 出力先の tableId
    524                scope                   = "session";                            // 出力先の scope
    525                masterTableId   = HybsSystem.TBL_MDL_KEY;       // マスタテーブルの tableId
    526                masterScope             = "session";                            // マスタテーブルの scope
    527                slaveTableId    = HybsSystem.TBL_MDL_KEY;       // スレーブテーブルの tableId
    528                slaveScope              = "request";                            // スレーブテーブルの scope
    529                masterKeys              = null;                                         // マスタテーブルの集合処理を行う主キー
    530                slaveKeys               = null;                                         // スレーブテーブルの集合処理を行う主キー(null時=masterKeys)
    531                diffKeys                = null;                                         // マスタテーブルのDIFFERENCE時の差分カラム名
    532                unionClms               = null;                                         // スレーブからマスタへ追加するカラム名
    533                unionLbls               = null;                                         // 6.9.1.0 (2018/02/26) スレーブからマスタへ追加するラベル名
    534                nullDelClms             = null;                                         // 6.7.3.0 (2017/01/27) 値がnull時にレコードを削除
    535                modifyClms              = null;                                         // DIFFERENCE,CDKH時にスレーブからマスタへ値を更新するカラム名
    536                groupAddClms    = null;                                         // 5.1.4.0 (2010/03/01) masterKeysで集合処理するときに、相違データをCSV連結して残すカラム名
    537                noSideEffect    = false;                                        // テーブルモデルに対する副作用(true:ない/false:ある)
    538                useDiffData             = true;                                         // DIFFERENCE時に差分のスレーブデータを追加するかどうか
    539                useCheckOnly    = false;                                        // マスタテーブルの選択行のデータのみを対象に処理を行うかどうか
    540                display                 = true;
    541                stopZero                = false;                                        // 5.7.6.2 (2014/05/16) stopZero属性追加
    542                useSlaveLoop    = false;                                        // 6.7.3.0 (2017/01/27) useSlaveLoop属性追加
    543                isMainTrans             = true;                                         // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
    544                separator               = ",";
    545        }
    546
    547        /**
    548         * 指定のテーブルの指定のカラム(CSV)より、行番号をマップ化します。
    549         * なお、引数のテーブルについては、useGroup属性に応じて、主キーによるグループ処理を
    550         * 行うかどうか決定します。(グループ化処理を行うと、副作用が発生します。)
    551         *
    552         * @og.rev 4.3.2.0 (2008/09/11) マスタキー未指定時は何もしない
    553         * @og.rev 5.1.4.0 (2010/03/01) groupAddClms 追加
    554         * @og.rev 5.3.1.0 (2011/01/01) groupAddClms の separator指定対応
    555         * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    556         * @og.rev 6.3.1.1 (2015/07/10) Map作成時に、DBTableModel のグループ化を行うかどうか指定できるようにする。
    557         *
    558         * @param       table   マップ作成元のデータテーブル(副作用あり)
    559         * @param       keys    マップ作成の主キー(CSV形式)
    560         * @param       useCheckOnly    チェック行のみ対象 [true:する/false:しない]
    561         * @param       useGroup                主キーによるグループ処理 [true:する/false:しない]
    562         *
    563         * @return マップ化された主キーと行番号
    564         */
    565        private Map<String,Integer> makeKeyMap( final DBTableModel table, final String keys, final boolean useCheckOnly, final boolean useGroup ) {
    566
    567                // カラム名をカラム番号に変換します。
    568                final int[] clmNo = makeColumnNo( table,keys );
    569                final int   clmSize = clmNo.length;
    570                if( clmSize == 0 ) {    // マスタキー未指定時には全カラムを使用します。
    571                        return null;            // 4.3.2.0 (2008/09/11)
    572                }
    573
    574                // groupAddClms をカラム番号に変換します。
    575                final int[] grpClmNo = makeColumnNo( table,groupAddClms );
    576                final int   grpClmSize = grpClmNo.length;
    577
    578                final Map<String,Integer> tempMap = new LinkedHashMap<>();
    579
    580                // 注意：GROUP化の過程で テーブル件数が動的に変化します。
    581                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );                   // 6.1.0.0 (2014/12/26) refactoring
    582                for( int row=0; row<table.getRowCount(); row++ ) {
    583                        if( useCheckOnly && table.getModifyType( row ).isEmpty() ) {
    584                                continue;
    585                        }
    586
    587                        buf.setLength(0);                                                                                                       // 6.1.0.0 (2014/12/26) refactoring
    588                        for( int i=0; i<clmSize; i++ ) {
    589                                buf.append( table.getValue( row,clmNo[i] ) ).append( '|' );             // 6.0.2.5 (2014/10/31) char を append する。
    590                        }
    591                        // 主キー連結文字列
    592                        final String key = buf.toString().toUpperCase(Locale.JAPAN);            // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    593                        if( tempMap.containsKey( key ) ) {
    594                                // 6.3.1.1 (2015/07/10) Map作成時に、DBTableModel のグループ化を行うかどうか指定できるようにする。
    595                                if( useGroup ) {
    596                                        // 5.1.4.0 (2010/03/01) groupAddClms 追加
    597                                        final int orgRow = tempMap.get( key ).intValue() ;                              // 追加済みの行番号を取得
    598                                        for( int i=0; i<grpClmSize; i++ ) {
    599                                                final int clm    = grpClmNo[i];
    600                                                final String val1 = table.getValue( orgRow,clm ) ;                      // 既存の行・カラムのデータ
    601                                                final String val2 = table.getValue( row,clm ) ;                         // 削除する行・カラムのデータ
    602                                                // 5.3.1.0 (2011/01/01)
    603                                                table.setValueAt( val1 + separator + val2,orgRow,clm );         // CSV 連結、データを戻す。
    604                                        }
    605                                        table.removeValue( row );
    606                                        row-- ;
    607                                }
    608                        }
    609                        else {                                                  // まだ、未登録の場合
    610                                tempMap.put( key,Integer.valueOf( row ) );
    611                        }
    612                }
    613
    614                return tempMap;
    615        }
    616
    617        /**
    618         * 指定のテーブルの指定のカラム(CSV)より、行番号をマップ化します。
    619         * なお、引数のテーブルについては、useGroup属性に応じて、主キーによるグループ処理を
    620         * 行うかどうか決定します。(グループ化処理を行うと、副作用が発生します。)
    621         *
    622         * @og.rev 6.9.1.0 (2018/02/26) 新規追加
    623         *
    624         * @param       table   マップ作成元のデータテーブル(副作用なし) 通常は、ｽﾚｰﾌﾞﾃｰﾌﾞﾙ
    625         * @param       keys    マップ作成の主キー(CSV形式)  通常は、ﾏｽﾀｰｷｰ(ｽﾚｰﾌﾞとマッチングさせるためのキー)
    626         * @param       valClm  値の配列リストに設定するカラム列(CSV形式)  キーカラムと値カラム
    627         *
    628         * @return マップ化された主キーと値の配列リスト
    629         */
    630        private Map<String,List<String[]>> makeValMap( final DBTableModel table, final String keys, final String valClm ) {
    631                // カラム名をカラム番号に変換します。
    632                final int[] clmNo = makeColumnNo( table,keys );                 // ｷｰとなるカラムのCSV形式
    633                final int   clmSize = clmNo.length;
    634                if( clmSize == 0 ) {    // マスタキー未指定時には全カラムを使用します。
    635                        return null;
    636                }
    637
    638                final int[] valNo = makeColumnNo( table,valClm );               // 値のカラムのCSV形式          (PMD:6.9.9.4 (2018/10/01))
    639                final Map<String,List<String[]>> tempMap = new LinkedHashMap<>();
    640
    641                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    642                for( int row=0; row<table.getRowCount(); row++ ) {
    643                        buf.setLength(0);
    644                        for( int i=0; i<clmSize; i++ ) {
    645                                buf.append( table.getValue( row,clmNo[i] ) ).append( '|' );
    646                        }
    647                        // 値の取得
    648                        final String[] vals = new String[valNo.length];
    649                        for( int i=0; i<valNo.length; i++ ) {
    650                                vals[i] = table.getValue( row,valNo[i] );
    651                        }
    652
    653                        // 主キー連結文字列
    654                        final String key = buf.toString().toUpperCase(Locale.JAPAN);            // 大文字・小文字を区別しない。
    655                        tempMap.computeIfAbsent( key , k -> new ArrayList<String[]>() ).add( vals );
    656                }
    657
    658                return tempMap;
    659        }
    660
    661        /**
    662         * 指定のマスタ,スレーブテーブルを使用して 全体集合 処理を実行します。
    663         *
    664         * @param       masterTbl       マスターテーブルモデル
    665         * @param       slaveTbl        スレーブテーブルモデル
    666         *
    667         * @return      処理結果のテーブルモデル
    668         */
    669        private DBTableModel makeUnionAll( final DBTableModel masterTbl,final DBTableModel slaveTbl ) {
    670                final DBTableModel table = masterTbl;
    671
    672                for( int row=0; row<slaveTbl.getRowCount(); row++ ) {
    673                        final String[] vals = slaveTbl.getValues( row );
    674                        table.addColumnValues( vals );
    675                }
    676
    677                return table;
    678        }
    679
    680        /**
    681         * 指定のマスタ,スレーブテーブルを使用して 全体集合 処理を実行します。
    682         * スレーブ表は、マスタ表のチェックされた行を起点として登録されます。
    683         * チェックされていない場合は、スレーブ表は先頭から追加されます。
    684         *
    685         * @og.rev 4.3.2.0 (2008/09/11) 新規作成
    686         *
    687         * @param       masterTbl       マスターテーブルモデル
    688         * @param       slaveTbl        スレーブテーブルモデル
    689         *
    690         * @return      処理結果のテーブルモデル
    691         */
    692        private DBTableModel makeUnionSelrow( final DBTableModel masterTbl,final DBTableModel slaveTbl ) {
    693                final DBTableModel table = masterTbl;
    694
    695                final int insRowNo = getParameterRows().length > 0 ? getParameterRows()[0] + 1 : 0 ;
    696                for( int row=0; row<slaveTbl.getRowCount(); row++ ) {
    697                        final String[] vals = slaveTbl.getValues( row );
    698                        table.addValues( vals, insRowNo + row, false );
    699                }
    700
    701                return table;
    702        }
    703
    704        /**
    705         * 指定のマスタ,スレーブテーブルを使用して 和集合 処理を実行します。
    706         *
    707         * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    708         *
    709         * @param       masterTbl       マスターテーブルモデル
    710         * @param       masterMap       マスターテーブルの主キーマップ
    711         * @param       slaveTbl        スレーブテーブルモデル
    712         * @param       slaveMap        スレーブテーブルの主キーマップ
    713         *
    714         * @return      処理結果のテーブルモデル
    715         */
    716        private DBTableModel makeUnion( final DBTableModel masterTbl,final Map<String,Integer> masterMap,
    717                                                                        final DBTableModel slaveTbl,final Map<String,Integer> slaveMap ) {
    718                final DBTableModel table = masterTbl;
    719
    720                @SuppressWarnings("rawtypes")
    721                final Map.Entry[] entry = slaveMap.entrySet().toArray( new Map.Entry[slaveMap.size()] );
    722
    723                final int size = entry.length;
    724                for( int i=0; i<size; i++ ) {
    725                        String key  = (String)entry[i].getKey();
    726                        if( key != null ) { key = key.toUpperCase(Locale.JAPAN); }              // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    727                        if( ! masterMap.containsKey( key ) ) {          // マスタにスレーブデータが存在しない
    728                                final int row =  ((Integer)entry[i].getValue()).intValue();
    729                                final String[] vals = slaveTbl.getValues( row );
    730                                table.addColumnValues( vals );
    731                        }
    732                }
    733                return table;
    734        }
    735
    736        /**
    737         * 指定のマスタ,スレーブテーブルを使用して 積集合 処理を実行します。
    738         *
    739         * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    740         * @og.rev 6.2.5.1 (2015/06/12) Modify情報が書かれていると、DELETE状況が再セットされないため、削除されなかった。
    741         *
    742         * @param       masterTbl       マスターテーブルモデル
    743         * @param       masterMap       マスターテーブルの主キーマップ
    744         * @param       slaveMap        スレーブテーブルの主キーマップ
    745         *
    746         * @return      処理結果のテーブルモデル
    747         */
    748        private DBTableModel makeIntersect( final DBTableModel masterTbl,final Map<String,Integer> masterMap, final Map<String,Integer> slaveMap ) {
    749                final DBTableModel table = masterTbl;
    750
    751                @SuppressWarnings("rawtypes")
    752                final Map.Entry[] entry = masterMap.entrySet().toArray( new Map.Entry[masterMap.size()] );
    753
    754                // 6.2.5.1 (2015/06/12) 削除する行番号を記憶しておく。
    755                final List<Integer> rowList = new ArrayList<>();
    756
    757                // table.resetModify();         // 6.2.5.1 (2015/06/12) Modify情報をリセットしておく必要があった。
    758
    759                final int size = entry.length;
    760                for( int i=0; i<size; i++ ) {
    761                        String key  = (String)entry[i].getKey();
    762                        if( key != null ) { key = key.toUpperCase(Locale.JAPAN); }              // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    763                        if( ! slaveMap.containsKey( key ) ) {           // スレーブにマスタが存在しない
    764                                rowList.add( (Integer)entry[i].getValue() );    // 6.2.5.1 (2015/06/12) rowをセット
    765                        }
    766                }
    767
    768                // 行番号が変わらないように逆順削除します。
    769                // 6.2.5.1 (2015/06/12) rowを削除
    770                for( int i=rowList.size()-1 ; i>=0; i-- ) {
    771                        table.removeValue( rowList.get(i) );
    772                }
    773
    774                return table;
    775        }
    776
    777        /**
    778         * 指定のマスタ,スレーブテーブルを使用して 差集合 処理を実行します。
    779         *
    780         * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    781         * @og.rev 6.2.5.1 (2015/06/12) Modify情報が書かれていると、DELETE状況が再セットされないため、削除されなかった。
    782         *
    783         * @param       masterTbl       マスターテーブルモデル
    784         * @param       masterMap       マスターテーブルの主キーマップ
    785         * @param       slaveMap        スレーブテーブルの主キーマップ
    786         *
    787         * @return      処理結果のテーブルモデル
    788         */
    789        private DBTableModel makeMinus( final DBTableModel masterTbl,final Map<String,Integer> masterMap,
    790                                                                        final Map<String,Integer> slaveMap ) {
    791                final DBTableModel table = masterTbl;
    792
    793                @SuppressWarnings("rawtypes")
    794                final Map.Entry[] entry = masterMap.entrySet().toArray( new Map.Entry[masterMap.size()] );
    795
    796                // 6.2.5.1 (2015/06/12) 削除する行番号を記憶しておく。
    797                final List<Integer> rowList = new ArrayList<>();
    798
    799                // table.resetModify();         // 6.2.5.1 (2015/06/12) Modify情報をリセットしておく必要があった。
    800
    801                final int size = entry.length;
    802                for( int i=0; i<size; i++ ) {
    803                        String key  = (String)entry[i].getKey();
    804                        if( key != null ) { key = key.toUpperCase(Locale.JAPAN); }              // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    805                        if( slaveMap.containsKey( key ) ) {             // スレーブにマスタが存在する
    806                                rowList.add( (Integer)entry[i].getValue() );    // 6.2.5.1 (2015/06/12) rowをセット
    807                        }
    808                }
    809
    810                // 行番号が変わらないように逆順削除します。
    811                // 6.2.5.1 (2015/06/12) rowを削除
    812                for( int i=rowList.size()-1 ; i>=0; i-- ) {
    813                        table.removeValue( rowList.get(i) );
    814                }
    815
    816                return table;
    817        }
    818
    819        /**
    820         * 指定のマスタ,スレーブテーブルを使用して 差分集合 処理を実行します。
    821         *
    822         * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    823         * @og.rev 7.4.2.0 (2021/04/30) spanタグでunmatched 表示の中身のタグを削除します。
    824         *
    825         * @param       masterTbl       マスターテーブルモデル
    826         * @param       masterMap       マスターテーブルの主キーマップ
    827         * @param       slaveTbl        スレーブテーブルモデル
    828         * @param       slaveMap        スレーブテーブルの主キーマップ
    829         *
    830         * @return      処理結果のテーブルモデル
    831         */
    832        private DBTableModel makeDifference( final DBTableModel masterTbl,final Map<String,Integer> masterMap,
    833                                                                                 final DBTableModel slaveTbl ,final Map<String,Integer> slaveMap ) {
    834                final DBTableModel table = masterTbl;
    835
    836                // テーブルの差分属性のカラム番号を求めます。(マスタ、スレーブ共通)
    837                final int[] diffClmNo = makeColumnNo( table,diffKeys );
    838                final int diffClmSize = diffClmNo.length;
    839
    840                // スレーブからマスタへ値の再セットを行うカラム番号を求めます。(マスタ、スレーブ共通)
    841                final int[] modClmNo = makeColumnNo( table,modifyClms );
    842                final int modClmSize = modClmNo.length;
    843
    844                final int clmSize = table.getColumnCount();
    845                final DBTableModel newTable = DBTableModelUtil.newDBTable();
    846                newTable.init( clmSize );
    847
    848                // テーブルの全カラムを新たに作成するテーブルにコピーします。
    849                for( int i=0; i<clmSize; i++ ) {
    850                        newTable.setDBColumn( i,table.getDBColumn( i ) );
    851                }
    852
    853                // スレーブの先頭カラムが、WRITABLE かどうか
    854                final boolean writeFlag = "WRITABLE".equalsIgnoreCase( slaveTbl.getColumnName(0) );
    855
    856                @SuppressWarnings("rawtypes")
    857                final Map.Entry[] entry = masterMap.entrySet().toArray( new Map.Entry[masterMap.size()] );
    858
    859                final int size = entry.length;
    860                for( int i=0; i<size; i++ ) {
    861                        String key  = (String)entry[i].getKey();
    862                        if( key != null ) { key = key.toUpperCase(Locale.JAPAN); }              // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    863                        if( slaveMap.containsKey( key ) ) {             // スレーブにマスタが存在する
    864                                final int mrow =  ((Integer)entry[i].getValue()).intValue();
    865                                final int srow =  slaveMap.get( key ).intValue();
    866                                boolean unmatched = false;
    867                                for( int j=0; j<diffClmSize; j++ ) {
    868                                        final String mval = table.getValue( mrow,diffClmNo[j] );
    869                                        final String sval = slaveTbl.getValue( srow,diffClmNo[j] );
    870                                        if( mval != null && !mval.equalsIgnoreCase( sval ) ) { unmatched = true; break; }               // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    871                                }
    872
    873                                if( unmatched ) {               // 属性情報が異なる場合のみ処理
    874                                        // データのコピー
    875                                        String[] mvals = new String[clmSize];
    876                                        System.arraycopy( table.getValues( mrow ),0,mvals,0 ,clmSize );
    877
    878                                        // スレーブの値をマスタの値にセットする。
    879                                        for( int j=0; j<modClmSize; j++ ) {
    880                                                final String val = slaveTbl.getValue( srow,modClmNo[j] );
    881                                                mvals[modClmNo[j]] = val;
    882                                        }
    883                                        newTable.addColumnValues( mvals );
    884
    885                                        if( useDiffData ) {
    886                                                // データのコピー
    887                                                String[] svals = new String[clmSize];
    888                                                System.arraycopy( slaveTbl.getValues( srow ),0,svals,0 ,clmSize );
    889                                                if( writeFlag ) { svals[0] = "0"; }     // 書き込み不許可
    890                                                for( int j=0; j<diffClmSize; j++ ) {
    891                                                        final int dclmNo = diffClmNo[j];
    892                                                        final String mval = mvals[dclmNo];
    893                                                        final String sval = svals[dclmNo];
    894                                                        if( mval != null && !mval.equalsIgnoreCase( sval ) ) {          // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    895                                                                // 7.4.2.0 (2021/04/30) spanタグでunmatched 表示の中身のタグを削除します。
    896//                                                              svals[dclmNo] = "<span class=\"unmatched\">" + sval + "</span>" ;
    897                                                                svals[dclmNo] = "<span class=\"unmatched\">" + StringUtil.htmlFilter(sval) + "</span>" ;
    898                                                        }
    899                                                }
    900                                                newTable.addColumnValues( svals );
    901                                        }
    902                                }
    903                        }
    904                }
    905                return newTable;
    906        }
    907
    908        /**
    909         * 指定のマスタ,スレーブテーブルを使用して 値列合成 処理を実行します。
    910         *
    911         *   UNION_VAL は、スレーブテーブルの縦列を横列に割り当てるUNION_CLMの特殊版です。
    912         *   処理としては、そのまま割り当てるのではなく、スレーブテーブルの縦列の値と
    913         *   ヘッダーとして指定する、unionClms の値を比較して、下限値の最大値を割り当てます。
    914         *   つまり、ヘッダーの値と同じか、それ以下で、最も近い値を割り当てることになります。
    915         *   これは、時間的な推移を表現することになります。
    916         *     masterKeys：マスタとスレーブを関連付ける共通のキーとなるカラム
    917         *     slaveKeys ：スレーブの縦列を横列にするための、キーと値のカラム
    918         *     unionClms ：横列にするカラム名。この値とスレーブのキーと比較してセットするかどうかを決めます。
    919         *
    920         * @og.rev 6.9.1.0 (2018/02/26) 新規追加
    921         *
    922         * @param       masterTbl       マスターテーブルモデル
    923         * @param       mstrKeys        マスターキー
    924         * @param       slaveTbl        スレーブテーブルモデル
    925         * @param       slaveKeys       スレーブキー
    926         *
    927         * @return      処理結果のテーブルモデル
    928         */
    929        private DBTableModel makeUnionVal( final DBTableModel masterTbl , final String mstrKeys , final DBTableModel slaveTbl , final String slaveKeys ) {
    930
    931                final Map<String,List<String[]>> slvMap = makeValMap( slaveTbl,mstrKeys,slaveKeys );
    932
    933                final DBTableModel table = makeAddClm( masterTbl );
    934
    935                // カラム名をカラム番号に変換します。
    936                final int[] keyClmNo = makeColumnNo( table,mstrKeys );
    937
    938                final int[] mClmNo = makeColumnNo( table   ,unionClms );
    939//              final int   addSize = mClmNo.length;            // unionClms の個数なので、マスタ、スレーブは同一
    940
    941                final String[] valClms = StringUtil.csv2Array( unionClms );             //
    942
    943                // 突合せを行い、マッチするカラムについて、値をセットし直します。
    944                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    945                for( int row=0; row<table.getRowCount(); row++ ) {
    946                        final String[] mvals = table.getValues( row );
    947                        buf.setLength(0);
    948                        for( int i=0; i<keyClmNo.length; i++ ) {
    949                                buf.append( mvals[keyClmNo[i]] ).append( '|' );
    950                        }
    951                        // 主キー連結文字列
    952                        final String key = buf.toString().toUpperCase(Locale.JAPAN);            // 大文字・小文字を区別しない。
    953                        final List<String[]> slvVals = slvMap.get( key );
    954                        if( slvVals != null ) {
    955                                for( int j=0; j<valClms.length; j++ ) {                 // ﾃｰﾌﾞﾙのﾍｯﾀﾞｰ列
    956                                        for( final String[] svals : slvVals ) {         // 値の配列 [0]=比較ｷｰ [1]=設定値
    957                                                if( svals[0].compareTo( valClms[j] ) <= 0 ) {
    958                                                        table.setValueAt( svals[1] , row , mClmNo[j] );
    959                                                }
    960                                                else {
    961                                                        break;          // 値が超えれば、終了
    962                                                }
    963                                        }
    964                                }
    965                        }
    966                }
    967                table.resetModify();
    968
    969                return table;
    970        }
    971
    972        /**
    973         * 指定のマスタ,スレーブテーブルを使用して 列合成(UNION_CLM) 処理を実行します。
    974         *
    975         * すでに、マスタ にカラムが存在している場合は、値の書き換えを、
    976         * カラムが存在しなければ、カラムを追加します。
    977         * マスタとスレーブのデータ突合せ時のキーは、slaveKeys になります。
    978         * これは、masterMap を使用しないことを意味します。(masterKeys 指定によるGROUP化は
    979         * 行います。masterKeys を指定しない場合は、サマライズなしで処理します。)
    980         * 具体的には、マスタテーブルの複数の行に対して、スレーブデータの値が設定
    981         * される可能性があることを意味します。
    982         *
    983         * @og.rev 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    984         *
    985         * @param       masterTbl       マスターテーブルモデル
    986         * @param       slaveKeys       スレーブキー
    987         * @param       slaveTbl        スレーブテーブルモデル
    988         * @param       slaveMap        スレーブテーブルの主キーマップ
    989         *
    990         * @return      処理結果のテーブルモデル
    991         */
    992        private DBTableModel makeUnionClm( final DBTableModel masterTbl ,final String slaveKeys ,
    993                                                                                final DBTableModel slaveTbl ,final Map<String,Integer> slaveMap ) {
    994
    995                final DBTableModel table = makeAddClm( masterTbl );
    996
    997                // カラム名をカラム番号に変換します。
    998                final int[] keyClmNo = makeColumnNo( table,slaveKeys );
    999
    1000                final int[] mClmNo = makeColumnNo( table   ,unionClms );
    1001                final int[] sClmNo = makeColumnNo( slaveTbl,unionClms );
    1002                final int   addSize = mClmNo.length;            // unionClms の個数なので、マスタ、スレーブは同一
    1003
    1004                // 突合せを行い、マッチするカラムについて、値をセットし直します。
    1005                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );   // 6.1.0.0 (2014/12/26) refactoring
    1006                for( int row=0; row<table.getRowCount(); row++ ) {
    1007                        final String[] mvals = table.getValues( row );
    1008                        buf.setLength(0);                                                                               // 6.1.0.0 (2014/12/26) refactoring
    1009                        for( int i=0; i<keyClmNo.length; i++ ) {
    1010                                buf.append( mvals[keyClmNo[i]] ).append( '|' );         // 6.0.2.5 (2014/10/31) char を append する。
    1011                        }
    1012                        // 主キー連結文字列
    1013                        final String key = buf.toString().toUpperCase(Locale.JAPAN);            // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    1014                        if( slaveMap.containsKey( key ) ) {             // スレーブにマスタに対応するデータが存在する
    1015                                final int slvRow = slaveMap.get( key ).intValue();
    1016                                final String[] svals = slaveTbl.getValues( slvRow );            // スレーブの行番号
    1017                                for( int j=0; j<addSize; j++ ) {
    1018                                        mvals[mClmNo[j]] = svals[sClmNo[j]];
    1019                                }
    1020                                table.setValues( mvals,row );
    1021                        }
    1022                }
    1023                table.resetModify();
    1024
    1025                return table;
    1026        }
    1027
    1028        /**
    1029         * 指定のマスタテーブルに 列追加 処理を実行します。
    1030         *
    1031         * すでに、マスタ にカラムが存在している場合は、値の書き換えを、
    1032         * カラムが存在しなければ、カラムを追加します。
    1033         *
    1034         * @og.rev 6.9.1.0 (2018/02/26) unionLbls追加
    1035         *
    1036         * @param       masterTbl       マスターテーブルモデル
    1037         *
    1038         * @return      処理結果のテーブルモデル
    1039         */
    1040        private DBTableModel makeAddClm( final DBTableModel masterTbl ) {
    1041                final String[]  addClms  = StringUtil.csv2Array( unionClms );
    1042                final int       addClmSize = addClms.length;
    1043                boolean[] useAdd         = new boolean[addClmSize];
    1044                int addSize = 0;
    1045                for( int i=0; i<addClmSize; i++ ) {
    1046                        if( masterTbl.getColumnNo( addClms[i],false ) < 0 ) {   // 存在しなければ -1
    1047                                useAdd[i] = true;
    1048                                addSize++ ;
    1049                        }
    1050                        else {
    1051                                useAdd[i] = false;              // マスタに存在すれば、追加不要
    1052                        }
    1053                }
    1054
    1055                final int mstrClmSize = masterTbl.getColumnCount();
    1056                final int clmSize = mstrClmSize + addSize;
    1057
    1058                final DBTableModel table = DBTableModelUtil.newDBTable();
    1059                table.init( clmSize );
    1060                int clmNo = 0;
    1061                // マスタテーブルの全カラムを新たに作成するテーブルにコピーします。
    1062                for( int i=0; i<mstrClmSize; i++ ) {
    1063                        table.setDBColumn( clmNo++,masterTbl.getDBColumn( i ) );
    1064                }
    1065
    1066                // 6.9.1.0 (2018/02/26) unionLbls追加
    1067                final String[]  addLbls  = StringUtil.csv2Array( unionLbls , ',' , addClmSize );        // 無くてもaddClmSize 個の配列を作る。
    1068
    1069                // 追加するカラムを新たに作成するテーブルに追加します。
    1070                String[] addClmVal = new String[addSize];       // 追加分のみ
    1071                int addCnt = 0;
    1072                for( int i=0; i<addClmSize; i++ ) {
    1073                        if( useAdd[i] ) {
    1074//                              final DBColumn column = getDBColumn( addClms[i] );
    1075                                final DBColumn column = getResource().makeDBColumn( addClms[i] , addLbls[i] );  // 6.9.1.0 (2018/02/26)
    1076                                addClmVal[addCnt++] = nval( column.getDefault(),"" );
    1077                                table.setDBColumn( clmNo++,column );
    1078                        }
    1079                }
    1080                // 一旦、すべてのマスタデータを新テーブルにコピーします。
    1081                for( int row=0; row<masterTbl.getRowCount(); row++ ) {
    1082                        final String[] vals = new String[clmSize];
    1083                        System.arraycopy( masterTbl.getValues( row ),0,vals,0 ,mstrClmSize );   // マスタデータのコピー
    1084                        System.arraycopy( addClmVal,0,vals,mstrClmSize ,addSize );                              // 追加列情報の初期値
    1085                        table.addColumnValues( vals );
    1086                }
    1087
    1088                return table;
    1089        }
    1090
    1091        /**
    1092         * 指定のマスタテーブルを使用して グループ 処理を実行します。
    1093         *
    1094         * @param       masterTbl       マスターテーブルモデル
    1095         *
    1096         * @return      処理結果のテーブルモデル
    1097         */
    1098        private DBTableModel makeGroup( final DBTableModel masterTbl ) {
    1099                return masterTbl ;
    1100        }
    1101
    1102        /**
    1103         * 指定のマスタ,スレーブテーブルを使用して、改廃コード(A,C)を設定します。
    1104         * スレーブにデータがあれば、"C" を、なければ、"A" をセットします。
    1105         * "D" は、設定できません。
    1106         *
    1107         * @og.rev 6.3.1.1 (2015/07/10) 改廃コードを設定する CDKH アクションを追加
    1108         *
    1109         * @param       masterTbl       マスターテーブルモデル
    1110         * @param       masterMap       マスターテーブルの主キーマップ
    1111         * @param       slaveTbl        スレーブテーブルモデル
    1112         * @param       slaveMap        スレーブテーブルの主キーマップ
    1113         *
    1114         * @return      処理結果のテーブルモデル
    1115         */
    1116        private DBTableModel makeCdkh( final DBTableModel masterTbl,final Map<String,Integer> masterMap,
    1117                                                                                 final DBTableModel slaveTbl ,final Map<String,Integer> slaveMap ) {
    1118                final DBTableModel table = masterTbl;
    1119
    1120                // スレーブからマスタへ値の再セットを行うカラム番号を求めます。(マスタ、スレーブ共通)
    1121                final int[] modClmNo = makeColumnNo( table,modifyClms );
    1122                final int modClmSize = modClmNo.length;
    1123
    1124                @SuppressWarnings("rawtypes")
    1125                final Map.Entry[] entry = masterMap.entrySet().toArray( new Map.Entry[masterMap.size()] );
    1126
    1127                table.resetModify();            // リセットしておきます。
    1128
    1129                final int size = entry.length;
    1130                for( int i=0; i<size; i++ ) {
    1131                        String key  = (String)entry[i].getKey();
    1132                        if( key != null ) { key = key.toUpperCase(Locale.JAPAN); }              // 5.5.8.5 (2012/11/27) 大文字・小文字を区別しない。
    1133                        if( slaveMap.containsKey( key ) ) {                             // スレーブにマスタが存在する
    1134                                final int mrow =  ((Integer)entry[i].getValue()).intValue();
    1135                                table.setModifyType( mrow , "C" );                      // 一致すれば、C:変更タイプ
    1136
    1137                                // スレーブの値をマスタの値にセットする。
    1138                                final int srow = slaveMap.get( key ).intValue();
    1139                                for( int j=0; j<modClmSize; j++ ) {
    1140                                        final String val = slaveTbl.getValue( srow,modClmNo[j] );       // スレーブから取り出して
    1141                                        table.setValueAt( val,mrow,modClmNo[j] );                                       // マスタにセットする。
    1142                                }
    1143                        }
    1144                }
    1145
    1146                for( int row=0; row<table.getRowCount(); row++ ) {
    1147                        if( table.getModifyType( row ).isEmpty() ) {
    1148                                table.setModifyType( row , "A" );                       // 残りを、A:追加タイプ
    1149                        }
    1150                }
    1151
    1152                return table;
    1153        }
    1154
    1155        /**
    1156         * 指定の値がすべてnull(空文字列)の場合、レコードを削除します。
    1157         *
    1158         * @og.rev 6.7.3.0 (2017/01/27) 指定の値がすべてnull(空文字列)の場合、レコードを削除します。
    1159         *
    1160         * @param       table   マップ作成元のデータテーブル(副作用あり)
    1161         * @param       delClms null(空文字列)判定を行うカラム列(CSV形式)
    1162         *
    1163         * @return レコードが削除されたテーブル
    1164         */
    1165        private DBTableModel deleteRows( final DBTableModel table, final String delClms ) {
    1166
    1167                // カラム名をカラム番号に変換します。
    1168                final int[] clmNo = makeColumnNo( table,delClms );
    1169                final int   clmSize = clmNo.length;
    1170                if( clmSize == 0 ) {    // マスタキー未指定時には全カラムを使用します。
    1171                        return table;
    1172                }
    1173
    1174                // レコードの削除なので逆順に処理します。
    1175                for( int row=table.getRowCount()-1; row>=0; row-- ) {
    1176                        boolean isNull = true;
    1177                        for( int i=0; i<clmSize; i++ ) {
    1178                                if( !StringUtil.isNull( table.getValue( row,clmNo[i] ) ) ) {
    1179                                        isNull = false;
    1180                                        break;
    1181                                }
    1182                        }
    1183
    1184                        if( isNull ) { table.removeValue( row ); }
    1185                }
    1186
    1187                return table;
    1188        }
    1189
    1190        /**
    1191         * 指定のテーブルと同じテーブルを別オブジェクトとして作成します。
    1192         *
    1193         * @param       tbl     コピー元テーブルモデル
    1194         *
    1195         * @return      コピーされた新テーブルモデル
    1196         */
    1197        private DBTableModel cloneTable( final DBTableModel tbl ) {
    1198                final int clmSize = tbl.getColumnCount();
    1199
    1200                final DBTableModel table = DBTableModelUtil.newDBTable();
    1201                table.init( clmSize );
    1202
    1203                // テーブルの全カラムを新たに作成するテーブルにコピーします。
    1204                for( int i=0; i<clmSize; i++ ) {
    1205                        table.setDBColumn( i,tbl.getDBColumn( i ) );
    1206                }
    1207                // すべてのデータを新テーブルにコピーします。
    1208                for( int row=0; row<tbl.getRowCount(); row++ ) {
    1209                        final String[] vals = new String[clmSize];
    1210                        System.arraycopy( tbl.getValues( row ),0,vals,0 ,clmSize );     // データのコピー
    1211                        table.addColumnValues( vals );
    1212                }
    1213                return table;
    1214        }
    1215
    1216        /**
    1217         * 指定のテーブルより、カラム列名に対応するカラム番号配列を作成します。
    1218         *
    1219         * カラム名のCSVデータが 指定されない場合(clmcsv == null)は、長さ０の配列を返します。
    1220         *
    1221         * @param       table   テーブルモデル
    1222         * @param       clmcsv  カラム名のCSVデータ
    1223         *
    1224         * @return      カラム名に対応する、列番号配列(なければ、長さ０配列)
    1225         */
    1226        private int[] makeColumnNo( final DBTableModel table,final String clmcsv ) {
    1227
    1228                // マスタテーブルの差分属性のカラム番号を求めます。
    1229                final String[] clms = StringUtil.csv2Array( clmcsv );
    1230                int[] clmNo = new int[clms.length];
    1231
    1232                // カラム名をカラム番号に変換します。
    1233                for( int i=0; i<clms.length; i++ ) {
    1234                        clmNo[i] = table.getColumnNo( clms[i] );
    1235                }
    1236
    1237                return clmNo;
    1238        }
    1239
    1240        /**
    1241         * 【TAG】コマンド (NEW,RENEW)をセットします(初期値:NEW)。
    1242         *
    1243         * @og.tag
    1244         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
    1245         * フィールド定数値のいづれかを、指定できます。
    1246         * 初期値は NEW です。
    1247         *
    1248         * @param       cmd     コマンド (public static final 宣言されている文字列)
    1249         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.TableMergeTag.CMD_NEW">コマンド定数</a>
    1250         */
    1251        public void setCommand( final String cmd ) {
    1252                final String cmd2 = getRequestParameter( cmd );
    1253                if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
    1254        }
    1255
    1256        /**
    1257         * 【TAG】アクションを指定します[UNION_ALL/UNION/INTERSECT/MINUS/DIFFERENCE/UNION_CLM/UNION_VAL/ADD_CLM/GROUP/UNION_SELROW/CDKH/TABLE_REMOVE]。
    1258         *
    1259         * @og.tag
    1260         * 指定できるアクションは、全体集合(UNION_ALL)、全体集合(挿入位置指定)(UNION_SELROW)、和集合(UNION)
    1261         * 、積集合(INTERSECT)、差集合(MINUS)、差分集合(DIFFERENCE)、列合成(UNION_CLM)、値列合成(UNION_VAL)、列追加(ADD_CLM)、 グループ(GROUP)です。
    1262         * 列合成とグループ以外の処理では、カラム順とカラム数は同数でなければなりません。
    1263         * primaryKeys や unionClms などの指定のキー名は、マスタテーブルに存在する必要があります。
    1264         * マスタテーブルと同じカラム番号でスレーブテーブルよりデータを読み出します。
    1265         * (カラム名や属性は、異なってもかまいませんが、マスタテーブルに準拠します。)
    1266         * また、単独(マスタテーブルのみ)で、和集合と同等の、グループ(GROUP)を使用すると、指定の
    1267         * カラムでのユニーク化を行うことが可能になります。グループ処理では、先行優先とし、
    1268         * ２回目に現れた情報を削除することになります。グループ が指定された場合は、
    1269         * スレーブテーブルは無視されます。いずれの処理においても、集合処理を行う主キーで
    1270         * 一旦グループ化されます。全体集合(UNION_ALL)で処理する場合でも、主キーがユニークで
    1271         * ない場合は、マスター、スレーブの各テーブルで一旦グループ化された後で、マージされます。
    1272         * (マージ後には、同一主キーを持つ行は存在します。)
    1273         * 全体集合(UNION_ALL)の場合のみ、mergeKeys を指定する必要はありません。その場合は、
    1274         * キーなしのため、マスターとスレーブのテーブルを単に合成するだけになります。
    1275         *
    1276         * <table class="plain">
    1277         *   <caption>アクションの説明</caption>
    1278         *   <tr><th>action      </th><th>名称    </th><th>処理概要                                                                                                   </th><th>１</th><th>２</th><th>３</th><th>４</th><tr>
    1279         *   <tr><td>UNION_ALL   </td><td>全体集合</td><td>マスタとスレーブを合成                                                                      </td><td>○</td><td>○</td><td>　</td><td>　</td><tr>
    1280         *   <tr><td>UNION       </td><td>和集合  </td><td>マスタとスレーブのユニーク部のみ合成                                              </td><td>○</td><td>○</td><td>　</td><td>　</td><tr>
    1281         *   <tr><td>INTERSECT   </td><td>積集合  </td><td>マスタとスレーブのユニーク部が一致するマスタのみ選択              </td><td>○</td><td>○</td><td>　</td><td>　</td><tr>
    1282         *   <tr><td>MINUS       </td><td>差集合  </td><td>マスタからスレーブに存在するユニーク部を削除した残り              </td><td>○</td><td>○</td><td>　</td><td>　</td><tr>
    1283         *   <tr><td>DIFFERENCE  </td><td>差分集合</td><td>ユニーク部が一致し、差分カラムが異なるマスタのみ選択               </td><td>○</td><td>○</td><td>　</td><td>○</td><tr>
    1284         *   <tr><td>UNION_CLM   </td><td>列合成  </td><td>マスタとキー一致するスレーブのカラム情報を追加                 </td><td>○</td><td>○</td><td>○</td><td>　</td><tr>
    1285         *   <tr><td>UNION_VAL   </td><td>値列合成</td><td>マスタとキー一致するスレーブの縦列をカラムに追加                 </td><td>○</td><td>○</td><td>○</td><td>　</td><tr>
    1286         *   <tr><td>ADD_CLM     </td><td>列追加  </td><td>UNION_CLMとの違いは、カラムのみ追加することです。           </td><td>　</td><td>　</td><td>○</td><td>　</td><tr>
    1287         *   <tr><td>GROUP       </td><td>グループ</td><td>マスタのユニーク部化                                                                               </td><td>　</td><td>　</td><td>　</td><td>　</td><tr>
    1288         *   <tr><td>UNION_SELROW</td><td>全体集合</td><td>マスタとスレーブを合成(マスタ表のチェック行を起点に追加     </td><td>○</td><td>　</td><td>　</td><td>　</td><tr>
    1289         *   <tr><td>CDKH        </td><td>改廃CD  </td><td>改廃コードを設定                                                                                       </td><td>○</td><td>○</td><td>　</td><td>○</td><tr>
    1290         *   <tr><td>TABLE_REMOVE</td><td>TBL削除 </td><td>マスタテーブルオブジェクトを無条件で、削除します                       </td><td>　</td><td>　</td><td>　</td><td>　</td><tr>
    1291         * </table>
    1292         *
    1293         * ※：マスタテーブルオブジェクトは、常に必須
    1294         * １：スレーブテーブルオブジェクト必須
    1295         * ２：masterKeys 属性必須
    1296         * ３：unionClms 属性必須(スレーブテーブルのカラム名または追加するカラム名)
    1297         * ４：diffKeys 属性必須(DIFFERENCE時の差分カラム名)、modifyClms 属性使用可能
    1298         *
    1299         * @param       action アクション [UNION_ALL/UNION/INTERSECT/MINUS/DIFFERENCE/UNION_CLM/ADD_CLM/GROUP/UNION_SELROW/CDKH]
    1300         */
    1301        public void setAction( final String action ) {
    1302                this.action = nval( getRequestParameter( action ),this.action );
    1303        }
    1304
    1305        /**
    1306         * 【TAG】出力先のtableIdを指定します
    1307         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    1308         *
    1309         * @og.tag
    1310         * 集合処理結果の DBTableModel をメモリにセットする場合のキー(tableId)を指定します。
    1311         * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    1312         *
    1313         * @param       id テーブルID (sessionに登録する時のID)
    1314         * @see         org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY
    1315         */
    1316        public void setTableId( final String id ) {
    1317                tableId = nval( getRequestParameter( id ),tableId );
    1318        }
    1319
    1320        /**
    1321         * 【TAG】出力先のscopeを指定します(初期値:session)。
    1322         *
    1323         * @og.tag
    1324         * 集合処理結果の DBTableModel をメモリにセットする場合のスコープを指定します。
    1325         * ここでは、マスタやスレーブのスコープ設定が必要な為、superクラスのメソッドを
    1326         * オーバーライドしてこのオブジェクト内でキープしています。
    1327         * 初期値は、session です。
    1328         *
    1329         * @param       scope   出力先のscope
    1330         */
    1331        @Override
    1332        public void setScope( final String scope ) {
    1333                this.scope = nval( getRequestParameter( scope ),this.scope );
    1334        }
    1335
    1336        /**
    1337         * 【TAG】マスタテーブルのtableIdを指定します
    1338         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    1339         *
    1340         * @og.tag
    1341         * 集合処理のマスタとなる DBTableModel をメモリから取り出す場合のキー(tableId)を指定します。
    1342         * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    1343         *
    1344         * @param       masterTableId   マスタテーブルID
    1345         * @see         org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY
    1346         */
    1347        public void setMasterTableId( final String masterTableId ) {
    1348                this.masterTableId = nval( getRequestParameter( masterTableId ),this.masterTableId );
    1349        }
    1350
    1351        /**
    1352         * 【TAG】マスタテーブルのscopeを指定します(初期値:session)。
    1353         *
    1354         * @og.tag
    1355         * 集合処理のマスタとなる DBTableModel をメモリから取り出す場合のスコープを指定します。
    1356         * 初期値は、session です。
    1357         *
    1358         * @param       masterScope     マスタスコープ
    1359         */
    1360        public void setMasterScope( final String masterScope ) {
    1361                this.masterScope = nval( getRequestParameter( masterScope ),this.masterScope );
    1362        }
    1363
    1364        /**
    1365         * 【TAG】マスタテーブルの集合処理を行う主キーを指定します。
    1366         *
    1367         * @og.tag
    1368         * 集合処理を行う場合の、カラム名を、CSV形式(CSV形式)で指定します。
    1369         * このキーの組み合わせを元に、集合処理の突合せを行います。
    1370         * なお、アクションがグループ(GROUP)以外の処理では、マスタとスレーブのカラム数と
    1371         * 並び順は、同じでなければなりません。カラム名は、各々別々でもかまいません。
    1372         * アクションが全体集合(UNION_ALL)以外の場合は、必須属性になります。
    1373         *
    1374         * @param       masterKeys      マスタテーブル主キー (CSV形式)
    1375         */
    1376        public void setMasterKeys( final String masterKeys ) {
    1377                this.masterKeys = nval( getRequestParameter( masterKeys ),this.masterKeys );
    1378        }
    1379
    1380        /**
    1381         * 【TAG】スレーブテーブルの集合処理を行う主キーを指定します。
    1382         *
    1383         * @og.tag
    1384         * 集合処理を行う場合の、カラム名を、CSV形式(CSV形式)で指定します。
    1385         * このキーの組み合わせを元に、集合処理の突合せを行います。
    1386         * なお、アクションがグループ(GROUP)以外の処理では、マスタとスレーブのカラム数と
    1387         * 並び順は、同じでなければなりません。カラム名は、各々別々でもかまいません。
    1388         * null の場合は、masterKeys と同じとします。
    1389         *
    1390         * @param       slaveKeys       スレーブ主キー (CSV形式)
    1391         */
    1392        public void setSlaveKeys( final String slaveKeys ) {
    1393                this.slaveKeys = nval( getRequestParameter( slaveKeys ),this.slaveKeys );
    1394        }
    1395
    1396        /**
    1397         * 【TAG】マスタテーブルのDIFFERENCE時の差分カラム名を(CSV形式)指定します。
    1398         *
    1399         * @og.tag
    1400         * アクションが差分処理(DIFFERENCE)の場合に、差分チェックを行うカラム名を、
    1401         * CSV形式(CSV形式)で指定します。
    1402         * 差分処理とは、masterKeys で指定されたキーでは、マスタ、スレーブともに存在し
    1403         * かつ、このキー(diffKeys)で指定されたキーの値が異なるマスタレコードを
    1404         * 抜き出します。
    1405         * つまり、主キーは存在し、属性が異なる情報のピックアップになりますので、
    1406         * データ更新(UPDATE)対象を見つける場合に使用できます。
    1407         * アクションが差分処理(DIFFERENCE)の場合は、必須属性になります。
    1408         *
    1409         * @param       diffKeys        差分カラム名 (CSV形式)
    1410         * @see         #setMasterKeys( String )
    1411         */
    1412        public void setDiffKeys( final String diffKeys ) {
    1413                this.diffKeys = nval( getRequestParameter( diffKeys ),this.diffKeys );
    1414        }
    1415
    1416        /**
    1417         * 【TAG】スレーブテーブルのtableIdを指定します
    1418         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    1419         *
    1420         * @og.tag
    1421         * 集合処理のスレーブとなる DBTableModel をメモリから取り出す場合のキー(tableId)を指定します。
    1422         * なお、アクションがグループ(GROUP)の場合は、スレーブテーブルは使用されません。
    1423         * (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    1424         *
    1425         * @param       slaveTableId    スレーブテーブルID
    1426         * @see         org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY
    1427         */
    1428        public void setSlaveTableId( final String slaveTableId ) {
    1429                this.slaveTableId = nval( getRequestParameter( slaveTableId ),this.slaveTableId );
    1430        }
    1431
    1432        /**
    1433         * 【TAG】スレーブテーブルのscopeを指定します(初期値:session)。
    1434         *
    1435         * @og.tag
    1436         * 集合処理のスレーブとなる DBTableModel をメモリから取り出す場合のスコープを指定します。
    1437         * なお、アクションがグループ(GROUP)の場合は、スレーブテーブルは使用されません。
    1438         * 初期値は、session です。
    1439         *
    1440         * @param       slaveScope      スレーブスコープ
    1441         */
    1442        public void setSlaveScope( final String slaveScope ) {
    1443                this.slaveScope = nval( getRequestParameter( slaveScope ),this.slaveScope );
    1444        }
    1445
    1446        /**
    1447         * 【TAG】スレーブからマスタへ追加するカラム名をCSV形式で指定します。
    1448         *
    1449         * @og.tag
    1450         * アクションが列合成(UNION_CLM)、値列合成(UNION_VAL)または列追加(ADD_CLM)の場合に使用されます。
    1451         * 列合成(UNION_CLM)は、マスタとスレーブの主キーに対して、ここで指定のスレーブの
    1452         * カラム列名を、マスタの列に追加します。主キーがマッチしない行に関しては、
    1453         * カラムの初期値が適用されたデータを作成します。
    1454         * 列追加(ADD_CLM)は、マスタテーブルに指定のカラムを追加するだけです、スレーブテーブルは
    1455         * 参照しません。よって、主キーも指定不要です。
    1456         *
    1457         * @param       unionClms       列合成カラム名 (CSV形式)
    1458         */
    1459        public void setUnionClms( final String unionClms ) {
    1460                this.unionClms = nval( getRequestParameter( unionClms ),this.unionClms );
    1461        }
    1462
    1463        /**
    1464         * 【TAG】スレーブからマスタへ追加するラベルをCSV形式で指定します。
    1465         *
    1466         * @og.tag
    1467         * アクションが列合成(UNION_CLM)、値列合成(UNION_VAL)または列追加(ADD_CLM)の場合に、
    1468         * unionClmsと共に使用されます。
    1469         *
    1470         * 特に、値列合成(UNION_VAL)時のカラムは、縦列の値からカラムを作成する関係で、
    1471         * 通常カラムリソースに存在しません。
    1472         * そこで、キーをそのままヘッダーに表示する場合に、不都合が発生する場合があるため、
    1473         * ラベルを置き換える機能を用意します。
    1474         *
    1475         * @og.rev 6.9.1.0 (2018/02/26) unionLbls属性追加
    1476         *
    1477         * @param       unionLbls       列合成カラム名 (CSV形式)
    1478         */
    1479        public void setUnionLbls( final String unionLbls ) {
    1480                this.unionLbls = nval( getRequestParameter( unionLbls ),this.unionLbls );
    1481        }
    1482
    1483        /**
    1484         * 【TAG】指定の値がすべてnull(空文字列)の場合、レコードを削除するカラムをCSV形式で指定します。
    1485         *
    1486         * @og.tag
    1487         * アクションが(GROUP)で、指定のカラム列の値が、すべてnull(空文字列)の場合は、
    1488         * そのレコード自身を削除します。
    1489         *
    1490         * @og.rev 6.7.3.0 (2017/01/27) nullDelClms属性追加
    1491         *
    1492         * @param       nullDelClms     null(空文字列)の場合、レコードを削除するカラムをCSV形式で指定
    1493         */
    1494        public void setNullDelClms( final String nullDelClms ) {
    1495                this.nullDelClms = nval( getRequestParameter( nullDelClms ),this.nullDelClms );
    1496        }
    1497
    1498        /**
    1499         * 【TAG】スレーブからマスタへ値を更新するカラム名をCSV形式で指定します。
    1500         *
    1501         * @og.tag
    1502         * アクションが差分処理(DIFFERENCE)、改廃CD(CDKH)の場合に、結果にマスタテーブルが抜き出されますが、
    1503         * 更新する場合に、スレーブ特有のユニークキー(例：UNIQ)を用いて更新する場合、
    1504         * 指定のカラム値は、スレーブの値にセットしておきたい場合があります。
    1505         * ここでは、指定のカラムについて、値だけスレーブからマスタへセットします。
    1506         * なお、値の更新については、マスタとスレーブが同一キーという制約があります。
    1507         *
    1508         * @param       modifyClms      値更新カラム名 (CSV形式)
    1509         */
    1510        public void setModifyClms( final String modifyClms ) {
    1511                this.modifyClms = nval( getRequestParameter( modifyClms ),this.modifyClms );
    1512        }
    1513
    1514        /**
    1515         * 【TAG】集合処理するときに、相違データをCSV連結して残すカラム名をCSV形式で指定します。
    1516         *
    1517         * @og.tag
    1518         * masterKeysで集合処理するときに、通常、最初に見つかった行データのみ残りますが、
    1519         * ここに指定したカラムについては、発生都度、自分自身の情報に、CSV形式で連結して
    1520         * いきます。
    1521         * この操作により、本来削除された情報が、１行のCSV形式で取得できる効果が得られます。
    1522         * これは、value タグの action="APPEND" を、DBTableModel に対して実施するような感じです。
    1523         *
    1524         * @og.rev 5.1.4.0 (2010/03/01) 新規追加
    1525         *
    1526         * @param       groupAddClms    相違データCSV連結 (CSV形式)
    1527         */
    1528        public void setGroupAddClms( final String groupAddClms ) {
    1529                this.groupAddClms = nval( getRequestParameter( groupAddClms ),this.groupAddClms );
    1530        }
    1531
    1532        /**
    1533         * 【TAG】テーブルモデルに対する副作用の有無[true:ない/false:ある]を指定します(初期値:false:ある)。
    1534         *
    1535         * @og.tag
    1536         * すべての処理で、DBTableModel に対して、ユニーク化やグループ化などの集合処理を
    1537         * 行う過程で、マスタテーブルに対して直接処理を行うと、副作用が発生します。
    1538         * 同様に、スレーブテーブルにおいても、一旦キー列でグループ化されるため、副作用が
    1539         * 発生します。これは、無駄なメモリ領域の確保と、テーブル(マスタ、スレーブとも)の
    1540         * コピー処理時間の節約になります。初期値の設定も副作用がある状態になっています。
    1541         * ところが、都合によっては、色々な action を連続して行いたい場合など、毎回、
    1542         * データベースを検索するよりもメモリ上でコピーしたほうが都合がよいケースでは、
    1543         * 副作用が出ないように、noSideEffect="true" に設定します。
    1544         * ただし、マスタ、スレーブともテーブルをコピーを行い、結果のテーブルも派生する為、
    1545         * 通常、２つの領域(マスタと結果は同じテーブルに書かれる)で良い所を、５つの領域が
    1546         * 作成されます。
    1547         * 初期値は、副作用がある(noSideEffect="false")です。
    1548         *
    1549         * @param       noSideEffect    処理結果副作用 [true:ない/false:ある]
    1550         */
    1551        public void setNoSideEffect( final String noSideEffect ) {
    1552                this.noSideEffect = nval( getRequestParameter( noSideEffect ),this.noSideEffect );
    1553        }
    1554
    1555        /**
    1556         * 【TAG】差分のスレーブデータを結果テーブルに追加するかどうかを指定します(初期値:true)。
    1557         *
    1558         * @og.tag
    1559         * アクションが差分処理(DIFFERENCE)の場合に、結果にマスタテーブルが抜き出されますが、
    1560         * 差分対象のスレーブデータと比較したい場合があります。
    1561         * このフラグを true にセットすると、書込み禁止属性が付いた状態で、スレーブデータが
    1562         * 結果テーブルに追加されます。
    1563         * なお、この処理では、通常と異なり、マスタテーブルにはグループ化の副作用は発生しますが、
    1564         * 結果テーブルは新規に作成され、先頭行に必ず WRITABLE カラムが付加されます。
    1565         * 初期値は、true：追加する です。
    1566         *
    1567         * @param       flag    差分追加 [true:追加する/false:追加しない]
    1568         */
    1569        public void setUseDiffData( final String flag ) {
    1570                useDiffData = nval( getRequestParameter( flag ),useDiffData );
    1571        }
    1572
    1573        /**
    1574         * 【TAG】マスタテーブルの選択行のデータのみを対象に処理を行うかどうか[true:する/false:しない]を指定します(初期値:false)。
    1575         *
    1576         * @og.tag
    1577         * 処理対象のマスタテーブルについて、選択行が指定された場合に、選択行のみを処理対象に
    1578         * するか、全件を対象にするかを指定します。
    1579         * 積集合や差分集合など通常は、全件を対象にすることになりますが、列合成や列追加など、
    1580         * マスタテーブルに対してのみ作用を及ぼす処理では、選択行のみを対象に処理を行う事が
    1581         * 考えられます。その場合、初期グループ化と同じで、対象とする行が選択行のみになります。
    1582         * 初期値は、false：全件対象 です。
    1583         *
    1584         * @param       flag    選択行のみ対象 [true:選択行のみ/false:全件]
    1585         */
    1586        public void setUseCheckOnly( final String flag ) {
    1587                useCheckOnly = nval( getRequestParameter( flag ),useCheckOnly );
    1588        }
    1589
    1590        /**
    1591         * 【TAG】マージの結果を表示するかどうか[true:する/false:しない]を指定します(初期値:true)。
    1592         *
    1593         * @og.tag
    1594         * true で、マージ結果を表示します。 false では、何も表示しません(初期値:true)
    1595         * マスタテーブルの件数は、通常、キーでグループ化されるため、入力件数と異なります。
    1596         * 同様に、スレーブ件数も異なります。結果の件数は、処理結果が現実的かどうかの
    1597         * 判断に使用されます。
    1598         * 初期値は、true：表示する です。
    1599         *
    1600         * @param       flag    結果表示 [true:する/false:しない]
    1601         */
    1602        public void setDisplay( final String flag ) {
    1603                display = nval( getRequestParameter( flag ),display );
    1604        }
    1605
    1606        /**
    1607         * 【TAG】検索結果が０件のとき処理を停止するかどうか[true/false]を指定します(初期値:false[続行する])。
    1608         *
    1609         * @og.tag
    1610         * 初期値は、false(続行する)です。
    1611         *
    1612         * @og.rev 5.7.6.2 (2014/05/16) 新規追加
    1613         *
    1614         * @param  flag ０件時停止 [true:処理を中止する/false:続行する]
    1615         */
    1616        public void setStopZero( final String flag ) {
    1617                stopZero = nval( getRequestParameter( flag ),stopZero );
    1618        }
    1619
    1620        /**
    1621         * 【TAG】scope="request" のスレーブテーブルをループして使用するかどうか[true/false]を指定します(初期値:false[使用しない])。
    1622         *
    1623         * action="UNION_CLM" では、カラムを動的に追加していきます。これを、繰り返すことで、特定の処理結果を、
    1624         * カラム列にコピーしていく処理が可能になります。（クロステーブル的な処理です。）
    1625         * 内容的には、scope="request" の同一の DBTableModel を、初回に、scope="session" にコピーすることで、
    1626         * 以後、マスターテーブルとして処理を続けるというものです。
    1627         * 初回かどうかを判別するのは、scope="session" の DBTableModel が存在しない場合は、scope="request" のDBTableModel を
    1628         * scope="session" に移すだけの処理を行います。
    1629         * 以降は、scope="session" に、DBTableModel が存在するはずなので、これを、マスターテーブルとして使用します。
    1630         * scope="session" の DBTableModel を消すのは、action="TABLE_REMOVE" です。
    1631         *
    1632         * @og.tag
    1633         * 初期値は、false(使用しない)です。
    1634         *
    1635         * @og.rev 6.7.3.0 (2017/01/27) useSlaveLoop属性追加
    1636         *
    1637         * @param  flag スレーブテーブルをループして使用するかどうか [true:使用する/false:使用しない]
    1638         */
    1639        public void setUseSlaveLoop( final String flag ) {
    1640                useSlaveLoop = nval( getRequestParameter( flag ),useSlaveLoop );
    1641        }
    1642
    1643        /**
    1644         * 【TAG】(通常は使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:true)。
    1645         *
    1646         * @og.tag
    1647         * この値は、ファイルダウンロード処理に影響します。この値がtrueに指定された時にcommitされたDBTableModelが
    1648         * ファイルダウンロードの対象の表になります。
    1649         *
    1650         * このパラメーターは、通常、各タグにより実装され、ユーザーが指定する必要はありません。
    1651         * 但し、1つのJSP内でDBTableModelが複数生成される場合に、前に処理したDBTableModelについてファイルダウンロードをさせたい
    1652         * 場合は、後ろでDBTableModelを生成するタグで、明示的にこの値をfalseに指定することで、ファイルダウンロード処理の対象から
    1653         * 除外することができます。
    1654         *
    1655         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
    1656         *
    1657         * @param  flag メイントランザクションかどうか [true:メイン/false:その他]
    1658         */
    1659        public void setMainTrans( final String flag ) {
    1660                isMainTrans = nval( getRequestParameter( flag ),isMainTrans );
    1661        }
    1662
    1663        /**
    1664         * 【TAG】groupAddClmsで文字列を連結する項目区切り文字をセットします(初期値:",")。
    1665         *
    1666         * @og.tag
    1667         * groupAddClmsで文字列を連結する項目区切り文字をセットします(初期値:",")。
    1668         * 初期値は、"," に設定されています。
    1669         *
    1670         * @og.rev 5.3.1.0 (2011/01/01)
    1671         *
    1672         * @param   sepa        項目区切り文字 (初期値:",")
    1673         */
    1674        public void setSeparator( final String sepa ) {
    1675                separator = nval( getRequestParameter( sepa ),separator );
    1676        }
    1677
    1678        /**
    1679         * このオブジェクトの文字列表現を返します。
    1680         * 基本的にデバッグ目的に使用します。
    1681         *
    1682         * @return このクラスの文字列表現
    1683         * @og.rtnNotNull
    1684         */
    1685        @Override
    1686        public String toString() {
    1687                return ToString.title( this.getClass().getName() )
    1688                                .println( "VERSION"                     ,VERSION                )
    1689                                .println( "action"                      ,action                 )
    1690                                .println( "tableId"                     ,tableId                )
    1691                                .println( "scope"                       ,scope                  )
    1692                                .println( "masterTableId"       ,masterTableId  )
    1693                                .println( "masterScope"         ,masterScope    )
    1694                                .println( "slaveTableId"        ,slaveTableId   )
    1695                                .println( "slaveScope"          ,slaveScope             )
    1696                                .println( "masterKeys"          ,masterKeys             )
    1697                                .println( "diffKeys"            ,diffKeys               )
    1698                                .println( "unionClms"           ,unionClms              )
    1699                                .println( "nullDelClms"         ,nullDelClms    )
    1700                                .println( "modifyClms"          ,modifyClms             )
    1701                                .println( "noSideEffect"        ,noSideEffect   )
    1702                                .println( "useDiffData"         ,useDiffData    )
    1703                                .println( "useCheckOnly"        ,useCheckOnly   )
    1704                                .println( "display"                     ,display                )
    1705                                .println( "ACTION_LIST"         ,ACTION_SET             )
    1706                                .println( "Other..."    ,getAttributes().getAttribute() )                       // 6.4.3.4 (2016/03/11)
    1707                                .fixForm().toString() ;
    1708        }
    1709}