    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.DBConstValue;
    021import org.opengion.fukurou.util.StringUtil;
    022import org.opengion.fukurou.util.ToString;                                                                              // 6.1.1.0 (2015/01/17)
    023
    024import static org.opengion.fukurou.util.StringUtil.nval;
    025
    026import java.util.Map;
    027import java.util.LinkedHashMap;
    028import java.util.Locale;                                                                                                                // 6.4.1.2 (2016/01/22)
    029
    030/**
    031 * TableUpdateTag にﾊﾟﾗﾒｰﾀｰを渡す為のﾀｸﾞｸﾗｽです｡
    032 *
    033 * 汎用的なﾃﾞｰﾀﾍﾞｰｽ登録処理を行えるﾀｸﾞ tableUpdate ﾀｸﾞを新規作成します｡
    034 * これは、具体的なSLQを作成する tableUpdateParam ﾀｸﾞと組み合わせて使用できます｡
    035 * tableUpdate ﾀｸﾞは、queryType に JDBCTableUpdate を指定します｡基本的にこれだけ
    036 * です｡tableUpdateParam では、sqlType に、INSERT,COPY,UPDATE,MODIFY,DELETE の
    037 * どれかを指定する事で、SQL文のﾀｲﾌﾟを指定します｡COPY,MODIFY は command と
    038 * 関連を持たす為に追加しているﾀｲﾌﾟで、UPDATE,INSERT と同じ処理を行います｡
    039 * tableUpdateParam の table には、作成したい SQL のﾃｰﾌﾞﾙを指定します｡
    040 * where 属性は、検索結果の DBTableModel の更新時に使用する条件を指定します｡
    041 *
    042 * @og.formSample
    043 * ●形式：&lt;og:tableUpdate command="{&#064;command}" queryType="JDBCTableUpdate" &gt;
    044 *            &lt;og:tableUpdateParam
    045 *                sqlType       = "{&#064;sqlType}"       // INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE
    046 *                table         = "{&#064;TABLE_NAME}"    // 処理対象のﾃｰﾌﾞﾙ名
    047 *                names         = "{&#064;names}"         // 処理対象のｶﾗﾑ名
    048 *                omitNames     = "{&#064;omitNames}"     // 処理対象外のｶﾗﾑ名
    049 *                where         = "{&#064;where}"         // 処理対象を特定するｷｰ
    050 *                whereNames    = "{&#064;whereNames}"    // 処理対象を特定するｷｰ条件(where句)をCSV形式
    051 *                constKeys     = "{&#064;constKeys}"     // 処理ｶﾗﾑ名の中の固定情報ｶﾗﾑ名
    052 *                constVals     = "{&#064;constVals}"     // 処理ｶﾗﾑ名の中の固定情報設定値
    053 *                asNames       = "{&#064;asNames}"       // 別名を付けたｶﾗﾑ名(select A as B from TBL の B を指定)
    054 *                orgNames      = "{&#064;orgNames}"      // tableの実際のｶﾗﾑ名(select A as B from TBL の A を指定)
    055 *                funcKeys      = "{&#064;funcKeys}"      // 関数等を設定するｶﾗﾑ名
    056 *                funcVals      = "{&#064;funcVals}"      // 関数等の設定値
    057 *                logicalDelete = "{&#064;logicalDelete}" // sqlTypeがDELETEの場合にもUPDATE文を発行
    058 *            /&gt;
    059 *         &lt;/og:tableUpdate&gt;
    060 *
    061 * ●body：なし
    062 *
    063 * ●Tag定義：
    064 *   &lt;og:tableUpdateParam
    065 *       sqlType          ○【TAG】BODY部に書かれている SQLﾀｲﾌﾟを指定します(INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE)(必須)
    066 *       table            ○【TAG】処理対象のﾃｰﾌﾞﾙ名を指定します(必須)
    067 *       names              【TAG】処理対象のｶﾗﾑ名をCSV形式で複数指定します
    068 *       omitNames          【TAG】処理対象外のｶﾗﾑ名をCSV形式で複数指定します
    069 *       where              【TAG】処理対象を特定するｷｰ条件(where句)を指定します
    070 *       whereNames         【TAG】処理対象を特定するｷｰ条件(where句)をCSV形式で複数指定します
    071 *       insertOnly         【TAG】true に設定すると、sqlType="MERGE" 時のみ有効で、where 条件で存在すれば何もしない(初期値:false) 7.4.1.0 (2021/04/23)
    072 *       constKeys          【TAG】設定値を固定値と置き換える対象となるｶﾗﾑ名をCSV形式で複数指定します
    073 *       constVals          【TAG】設定値を固定値と置き換える対象となる設定値をCSV形式で複数指定します
    074 *       funcKeys           【TAG】関数等を設定するｶﾗﾑ名をCSV形式で複数指定します
    075 *       funcVals           【TAG】関数等の設定値をCSV形式で複数指定します
    076 *       asNames            【TAG】別名を付けたｶﾗﾑ名(select A as B from TBL の B を指定)をCSV形式で複数指定します
    077 *       orgNames           【TAG】tableの実際のｶﾗﾑ名(select A as B from TBL の A を指定)をCSV形式で複数指定します
    078 *       quotCheck          【TAG】ﾘｸｴｽﾄ情報の ｼﾝｸﾞﾙｸｫｰﾄ(') 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します (初期値:USE_SQL_INJECTION_CHECK[=true])
    079 *       constObjKey        【TAG】固定情報ｶﾗﾑの処理ｵﾌﾞｼﾞｪｸﾄを特定するｷｰを設定します(初期値:SYSTEM_ID)
    080 *       logicalDelete      【TAG】sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します(初期値:false)
    081 *       caseKey            【TAG】このﾀｸﾞ自体を利用するかどうかの条件ｷｰを指定します(初期値:null)
    082 *       caseVal            【TAG】このﾀｸﾞ自体を利用するかどうかの条件値を指定します(初期値:null)
    083 *       caseNN             【TAG】指定の値が、null/ｾﾞﾛ文字列 でない場合(Not Null=NN)は、このﾀｸﾞは使用されます(初期値:判定しない)
    084 *       caseNull           【TAG】指定の値が、null/ｾﾞﾛ文字列 の場合は、このﾀｸﾞは使用されます(初期値:判定しない)
    085 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このﾀｸﾞは使用されます(初期値:判定しない)
    086 *       debug              【TAG】ﾃﾞﾊﾞｯｸﾞ情報を出力するかどうか[true/false]を指定します(初期値:false)
    087 *   /&gt;
    088 *
    089 * ●使用例
    090 *    ･【entry.jsp】
    091 *         &lt;og:tableUpdate command="{&#064;command}" queryType="JDBCTableUpdate" &gt;
    092 *            &lt;og:tableUpdateParam
    093 *               sqlType  = "{&#064;sqlType}"
    094 *               table    = "{&#064;MEM.TABLE_NAME}"
    095 *               where    = "ROWID = [ROWID]"
    096 *            /&gt;
    097 *         &lt;/og:tableUpdate&gt;
    098 *
    099 * @og.rev 3.8.8.0 (2007/12/22) 新規作成
    100 * @og.rev 4.1.2.0 (2008/03/12) 実装の大幅な修正
    101 * @og.rev 7.2.9.1 (2020/10/23) TableUpdateParamTag のﾏｰｼﾞ(UPDATE,INSERT)対応
    102 * @og.group DB登録
    103 *
    104 * @version  4.0
    105 * @author   Kazuhiko Hasegawa
    106 * @since    JDK5.0,
    107 */
    108public class TableUpdateParamTag extends CommonTagSupport {
    109        /** このプログラムのVERSION文字列を設定します。   {@value} */
    110        private static final String VERSION = "8.3.0.3 (2022/08/26)" ;
    111        private static final long serialVersionUID = 830320220826L ;
    112
    113        /** sqlType属性に設定できる値                    {@value} */
    114//      public static final String SQL_TYPE  = "|INSERT|COPY|UPDATE|MODIFY|DELETE|" ;
    115        public static final String SQL_TYPE  = "|INSERT|COPY|UPDATE|MODIFY|DELETE|MERGE|" ;             // 7.2.9.1 (2020/10/23)
    116
    117        // 3.8.0.4 (2005/08/08) 印刷時に使用するｼｽﾃﾑID
    118        private static final String SYSTEM_ID =HybsSystem.sys( "SYSTEM_ID" );
    119
    120        // 4.3.6.0 (2009/05/01) ﾃﾞﾌｫﾙﾄで利用するconstObjのｼｽﾃﾑﾘｿｰｽ名
    121        private static final String DEFAULT_CONST_OBJ = HybsSystem.sys( "DEFAULT_CONST_CLASS" );
    122
    123        private String          sqlType         ;                                                                                       // INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE
    124        private String          table           ;                                                                                       // 処理対象のﾃｰﾌﾞﾙ名
    125        private String[]        names           ;                                                                                       // 処理対象のｶﾗﾑ名
    126        private String          omitNames       = ",ROWID,ROWNUM,WRITABLE,";                            // 処理対象外のｶﾗﾑ名
    127        private String          where           ;                                                                                       // 処理対象を特定するｷｰ
    128        private String          whereNames      ;                                                                                       // 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のｶﾗﾑ名
    129        private boolean         insertOnly;                                                                                             // 7.4.1.0 (2021/04/23) sqlType="MERGE" 時のみ有効で、where 条件で存在すれば何もしない
    130        private String[]        constKeys       ;                                                                                       // 処理ｶﾗﾑ名の中の固定情報ｶﾗﾑ名
    131        private String[]        constVals       ;                                                                                       // 処理ｶﾗﾑ名の中の固定情報設定値
    132        private String[]        funcKeys        ;                                                                                       // 5.5.1.9 (2012/04/19) 関数等を設定するｶﾗﾑ名
    133        private String[]        funcVals        ;                                                                                       // 5.5.1.9 (2012/04/19) 関数等の設定値
    134        private String[]        asNames         ;                                                                                       // 5.5.1.9 (2012/04/19) 別名を付けたｶﾗﾑ名(select A as B from TBL の B を指定)
    135        private String[]        orgNames        ;                                                                                       // 5.5.1.9 (2012/04/19) tableの実際のｶﾗﾑ名(select A as B from TBL の A を指定)
    136        private String          constObjKey     = SYSTEM_ID;                                                            // 固定情報ｶﾗﾑの処理ｵﾌﾞｼﾞｪｸﾄを特定するｷｰ
    137        private boolean         quotCheck       = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );
    138        private boolean         logicalDelete;                                                                                  // 4.3.7.0 (2009/06/01) sqlTypeがDELETEの場合にもUPDATE文を発行
    139
    140        /**
    141         * ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰ
    142         *
    143         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    144         */
    145        public TableUpdateParamTag() { super(); }               // これも、自動的に呼ばれるが、空のﾒｿｯﾄﾞを作成すると警告されるので、明示的にしておきます｡
    146
    147        /**
    148         * Taglibの開始ﾀｸﾞが見つかったときに処理する doStartTag() を ｵｰﾊﾞｰﾗｲﾄﾞします｡
    149         *
    150         * @og.rev 5.5.1.9 (2012/04/19) ｴﾗｰﾁｪｯｸを先に行います｡
    151         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
    152         * @og.rev 7.0.1.0 (2018/10/15) XHTML → HTML5 対応(空要素の、"／＞" 止めを、"＞" に変更します)｡
    153         *
    154         * @return      後続処理の指示( SKIP_BODY )
    155         */
    156        @Override
    157        public int doStartTag() {
    158                if( !useTag() ) { return SKIP_BODY ; }                                                                  // 6.3.4.0 (2015/08/01)
    159
    160                // constKeys,constVals の個数チェック
    161                if( constKeys != null ) {
    162                        if( constVals == null || constKeys.length != constVals.length ) {
    163//                              final String errMsg = "<b>constKeys と、constVals の個数が異なります。</b><br />"
    164                                final String errMsg = "<b>constKeys と、constVals の個数が異なります。</b><br>"             // 7.0.1.0 (2018/10/15)
    165                                                                        + " constKeys=[" + StringUtil.array2csv( constKeys ) + "]"
    166                                                                        + " constVals=[" + StringUtil.array2csv( constVals ) + "]" ;
    167                                throw new HybsSystemException( errMsg );
    168                        }
    169                }
    170
    171                // funcKeys,funcVals の個数チェック
    172                if( funcKeys != null ) {
    173                        if( funcVals == null || funcKeys.length != funcVals.length ) {
    174//                              final String errMsg = "<b>funcKeys と、funcVals の個数が異なります。</b><br />"
    175                                final String errMsg = "<b>funcKeys と、funcVals の個数が異なります。</b><br>"               // 7.0.1.0 (2018/10/15)
    176                                                                        + " funcKeys=[" + StringUtil.array2csv( funcKeys ) + "]"
    177                                                                        + " funcVals=[" + StringUtil.array2csv( funcVals ) + "]" ;
    178                                throw new HybsSystemException( errMsg );
    179                        }
    180                }
    181
    182                // asNames,orgNames の個数チェック
    183                if( orgNames != null ) {
    184                        if( asNames == null || orgNames.length != asNames.length ) {
    185//                              final String errMsg = "<b>orgNames と、asNames の個数が異なります。</b><br />"
    186                                final String errMsg = "<b>orgNames と、asNames の個数が異なります。</b><br>"                // 7.0.1.0 (2018/10/15)
    187                                                                        + " orgNames=[" + StringUtil.array2csv( orgNames ) + "]"
    188                                                                        + " asNames=[" + StringUtil.array2csv( asNames ) + "]" ;
    189                                throw new HybsSystemException( errMsg );
    190                        }
    191                }
    192
    193                return SKIP_BODY ;      // Body を評価しない
    194        }
    195
    196        /**
    197         * Taglibの終了ﾀｸﾞが見つかったときに処理する doEndTag() を ｵｰﾊﾞｰﾗｲﾄﾞします｡
    198         *
    199         * @og.rev 4.3.7.0 (2009/06/01) 論理削除対応
    200         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
    201         * @og.rev 7.2.9.1 (2020/10/23) TableUpdateParamTag のﾏｰｼﾞ(UPDATE,INSERT)対応
    202         * @og.rev 7.4.1.0 (2021/04/23) sqlType="MERGE" 時のみ有効で、where 条件で存在すれば何もしない
    203         * @og.rev 8.3.0.3 (2022/08/26) sqlType="MERGE" の場合、UPDATE文 に追加関連固定ｶﾗﾑｷｰが追加される不具合対応
    204         *
    205         * @return      後続処理の指示
    206         */
    207        @Override
    208        public int doEndTag() {
    209                debugPrint();
    210//              if( !useTag() ) { return EVAL_PAGE ; }                                                                  // 6.3.4.0 (2015/08/01)
    211                if( !useTag() || sqlType == null ) { return EVAL_PAGE ; }                               // 7.2.9.1 (2020/10/23) sqlType == null の時は、何もしない。
    212
    213                final TableUpdateTag updateTag = (TableUpdateTag)findAncestorWithClass( this,TableUpdateTag.class );
    214                if( updateTag == null ) {
    215                        final String errMsg = "<b>" + getTagName() + "ﾀｸﾞは、TableUpdateTagの内側(要素)に記述してください。</b>";
    216                        throw new HybsSystemException( errMsg );
    217                }
    218
    219                final String upSqlType = updateTag.getSqlType() ;
    220
    221                // 7.2.9.1 (2020/10/23) TableUpdateParamTag のﾏｰｼﾞ(UPDATE,INSERT)対応
    222                final boolean useInsert = "INSERT,COPY,MERGE".contains( sqlType ) ;
    223                final boolean useUpdate = "UPDATE,MODIFY,MERGE".contains( sqlType ) || "DELETE".contains( sqlType ) && logicalDelete ;
    224                final boolean useDelete = "DELETE".equals( sqlType ) && !logicalDelete ;
    225                final boolean useMerge  = "MERGE".contains( sqlType ) ;                                 // 8.3.0.3 (2022/08/26) Add
    226
    227                if( upSqlType == null || upSqlType.equals( sqlType ) ) {
    228                        // 通常の names ｶﾗﾑ配列を設定します｡
    229                        if( names == null ) { names = updateTag.getNames(); }
    230                        final NamesData namesData = makeNamesData( names );
    231
    232                        // 8.3.0.3 (2022/08/26) Modify
    233                        if( useInsert ) {
    234//                              updateTag.setQuery( "INSERT",getInsertSQL( namesData ) );
    235                                final NamesData namesData1 = useMerge ? namesData.newInstance() : namesData;
    236                                updateTag.setQuery( "INSERT",getInsertSQL( namesData1 ) );
    237                        }
    238                        if( useUpdate ) {
    239                                if( insertOnly ) {                                                                                              // 7.4.1.0 (2021/04/23)
    240                                        updateTag.setQuery( "SELECT",getSelectSQL() );
    241                                }
    242                                // 8.3.0.3 (2022/08/26) Modify
    243                                else {
    244//                                      updateTag.setQuery( "UPDATE",getUpdateSQL( namesData ) );
    245                                        final NamesData namesData2 = useMerge ? namesData.newInstance() : namesData;
    246                                        updateTag.setQuery( "UPDATE",getUpdateSQL( namesData2 ) );
    247                                }
    248                        }
    249                        if( useDelete ) {
    250                                updateTag.setQuery( "DELETE",getDeleteSQL() );
    251                        }
    252                }
    253
    254//              // 7.2.9.1 (2020/10/23) TableUpdateParamTag のﾏｰｼﾞ(UPDATE,INSERT)対応
    255//              if( upSqlType == null || upSqlType.equals( sqlType ) ||  ) {
    256//                      String query = null;
    257//                      if( "INSERT".equalsIgnoreCase( sqlType ) || "COPY".equalsIgnoreCase( sqlType ) ) {
    258//                              query = getInsertSQL( namesData );
    259//                      }
    260//                      else if( "UPDATE".equalsIgnoreCase( sqlType ) || "MODIFY".equalsIgnoreCase( sqlType )
    261//                                      || ( "DELETE".equalsIgnoreCase( sqlType ) && logicalDelete ) ) { // 4.3.7.0 (2009/06/01)
    262//                              query = getUpdateSQL( namesData );
    263//                      }
    264//                      else if( "DELETE".equalsIgnoreCase( sqlType ) ) {
    265//                              query = getDeleteSQL();
    266//                      }
    267//
    268//                      jspPrint( query );
    269//              }
    270
    271                return EVAL_PAGE ;
    272        }
    273
    274        /**
    275         * ﾀｸﾞﾘﾌﾞｵﾌﾞｼﾞｪｸﾄをﾘﾘｰｽします｡
    276         * ｷｬｯｼｭされて再利用されるので、ﾌｨｰﾙﾄﾞの初期設定を行います｡
    277         *
    278         * @og.rev 4.3.7.0 (2009/06/01) logicalDelete属性追加
    279         * @og.rev 5.5.1.9 (2012/04/19) asNames、orgNames、funcKeys、funcVals属性追加
    280         * @og.rev 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のｶﾗﾑ名
    281         * @og.rev 7.4.1.0 (2021/04/23) sqlType="MERGE" 時のみ有効で、where 条件で存在すれば何もしない
    282         */
    283        @Override
    284        protected void release2() {
    285                super.release2();                                                                                                               // 3.5.6.0 (2004/06/18) 追加(抜けていた)
    286                sqlType                 = null;                                                                                                 // INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE
    287                table                   = null;                                                                                                 // 処理対象のﾃｰﾌﾞﾙ名
    288                names                   = null;                                                                                                 // 処理対象のｶﾗﾑ名
    289                omitNames               = ",ROWID,ROWNUM,WRITABLE,";                                                    // 処理対象外のｶﾗﾑ名
    290                where                   = null;                                                                                                 // 処理対象を特定するｷｰ
    291                whereNames              = null;                                                                                                 // 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のｶﾗﾑ名
    292                insertOnly              = false;                                                                                                // 7.4.1.0 (2021/04/23) sqlType="MERGE" 時のみ有効で、where 条件で存在すれば何もしない
    293                constKeys               = null;                                                                                                 // 処理ｶﾗﾑ名の中の固定情報ｶﾗﾑ名
    294                constVals               = null;                                                                                                 // 処理ｶﾗﾑ名の中の固定情報設定値
    295                quotCheck               = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );
    296                constObjKey             = SYSTEM_ID;                                                                                    // 固定情報ｶﾗﾑの処理ｵﾌﾞｼﾞｪｸﾄを特定するｷｰ
    297                logicalDelete   = false;                                                                                                // 4.3.7.0 (2009/06/01)
    298                funcKeys                = null;                                                                                                 // 5.5.1.9 (2012/04/19) 関数等を設定するｶﾗﾑ名
    299                funcVals                = null;                                                                                                 // 5.5.1.9 (2012/04/19) 関数等の設定値
    300                asNames                 = null;                                                                                                 // 5.5.1.9 (2012/04/19) 別名を付けたｶﾗﾑ名(select A as B from TBL の B を指定)
    301                orgNames                = null;                                                                                                 // 5.5.1.9 (2012/04/19) tableの実際のｶﾗﾑ名(select A as B from TBL の A を指定)
    302        }
    303
    304        /**
    305         * 【TAG】BODY部に書かれている SQLﾀｲﾌﾟを指定します｡
    306         *
    307         * @og.tag
    308         * SQLﾀｲﾌﾟは、INSERT,COPY,UPDATE,MODIFY,DELETE,MERGE の中から指定する
    309         * 必要があります｡これらは、内部に書かれるSQLの形式を指定するのに使用します｡
    310         * 内部処理は、DBTableModelの改廃ｺｰﾄﾞ(A,C,D)に対して使用される
    311         * SQL を選択する場合の情報に使用されます｡
    312         * なお、COPY と MODIFY は、command で指定できる簡易機能として用意しています｡
    313         * 上位の TableUpdateTag の sqlType 属性 と同じsqlType 属性の場合のみ、SQL文を
    314         * 合成・出力します｡(上位のsqlTypeがnullの場合は、無条件実行します｡)
    315         * 指定のﾀｲﾌﾟが、異なる場合は、なにも処理を行いません｡
    316         *
    317         * @param       type    SQLﾀｲﾌﾟ [INSERT/COPY/UPDATE/MODIFY/DELETE/MERGE]
    318         */
    319        public void setSqlType( final String type ) {
    320                sqlType = nval( getRequestParameter( type ),sqlType );
    321                if( sqlType != null && SQL_TYPE.indexOf( "|" + sqlType + "|" ) < 0 ) {
    322                        sqlType = null;
    323                }
    324        }
    325
    326        /**
    327         * 【TAG】処理対象のﾃｰﾌﾞﾙ名を指定します｡
    328         *
    329         * @og.tag
    330         * ﾃｰﾌﾞﾙ名を指定することで、sqlTypeに応じた QUERYを生成することが出来ます｡
    331         * 生成する場合のｶﾗﾑを特定する場合は、names 属性で指定できます｡
    332         * また、WHERE条件は、where属性で指定します｡
    333         *
    334         * @param       tbl     ﾃｰﾌﾞﾙ名
    335         * @see         #setNames( String )
    336         * @see         #setWhere( String )
    337         * @see         #setSqlType( String )
    338         */
    339        public void setTable( final String tbl ) {
    340                table = nval( getRequestParameter( tbl ),table );
    341        }
    342
    343        /**
    344         * 【TAG】処理対象のｶﾗﾑ名をCSV形式で複数指定します｡
    345         *
    346         * @og.tag
    347         * 生成するQUERYのｶﾗﾑ名をCSV形式(CSV)で複数指定します｡
    348         * 指定がない場合は、DBTableModel の全ｶﾗﾑ(※)を使用して、QUERYを構築します｡
    349         * 一般に、ﾃｰﾌﾞﾙ結合してDBTableModelを構築した場合は、登録すべきｶﾗﾑを
    350         * 指定する必要があります｡
    351         * (※)正確には、DBTableModel の全ｶﾗﾑのうち、ROWID,ROWNUM,WRITABLE ｶﾗﾑは
    352         * 無視します｡
    353         * 分解方法は、通常のﾊﾟﾗﾒｰﾀ取得後に、CSV分解します｡
    354         *
    355         * @og.rev 3.8.8.5 (2007/03/09) 通常のﾊﾟﾗﾒｰﾀ取得後に、CSV分解に戻します｡
    356         *
    357         * @param       nms     ｶﾗﾑ名 (CSV形式)
    358         * @see         #setTable( String )
    359         * @see         #setOmitNames( String )
    360         */
    361        public void setNames( final String nms ) {
    362                names = StringUtil.csv2Array( getRequestParameter( nms ) );
    363                if( names.length == 0 ) { names = null; }
    364        }
    365
    366        /**
    367         * 【TAG】処理対象外のｶﾗﾑ名をCSV形式で複数指定します｡
    368         *
    369         * @og.tag
    370         * 生成するQUERYのｶﾗﾑ名に指定しないｶﾗﾑ名をCSV形式(CSV)で複数指定します｡
    371         * 指定がない場合は、DBTableModel の全ｶﾗﾑ(※)を使用して、QUERYを構築します｡
    372         * ﾃｰﾌﾞﾙ結合などで、処理したくないｶﾗﾑ数の方が少ない場合に、names ですべてを
    373         * 指定するより少ない記述ですみます｡
    374         * (※)正確には、DBTableModel の全ｶﾗﾑのうち、ROWID,ROWNUM,WRITABLE ｶﾗﾑは
    375         * 無視します｡
    376         *
    377         * @param       nms     ｶﾗﾑ名 (CSV形式)
    378         * @see         #setTable( String )
    379         * @see         #setNames( String )
    380         */
    381        public void setOmitNames( final String nms ) {
    382                omitNames = omitNames + nval( getRequestParameter( nms ),"" ) + ",";
    383        }
    384
    385        /**
    386         * 【TAG】処理対象を特定するｷｰ条件(where句)を指定します｡
    387         *
    388         * @og.tag
    389         * 生成するQUERYのwhere 句を指定します｡通常の WHERE 句の書き方と同じで、
    390         * DBTableModelの値を割り当てたい箇所に[ｶﾗﾑ名] を記述します｡
    391         * 文字列の場合、設定値をｾｯﾄするときに、ｼﾝｸﾞﾙｺｰﾃｰｼｮﾝを
    392         * 使用しますが、[ｶﾗﾑ名]で指定する場合は、その前後に、(')ｼﾝｸﾞﾙ
    393         * ｺｰﾃｰｼｮﾝは、不要です｡
    394         * {&#064;XXXX}変数を使用する場合は、ﾊﾟｰｽ時に固定文字に置き換えられる為、
    395         * 文字列指定時の(')ｼﾝｸﾞﾙｺｰﾃｰｼｮﾝが必要になります｡
    396         * ※ 5.5.8.5 (2012/11/27) whereNames 属性と併用した場合は、where が、and を付けて、文字列結合されます｡
    397         * 例：FGJ='1' and CLM=[CLM] and SYSTEM_ID in ([SYSID],'**') and KBSAKU='{&#064;KBSAKU}'
    398         *
    399         * @param       wr      検索条件 (where句)
    400         */
    401        public void setWhere( final String wr ) {
    402                where = nval( getRequestParameter( wr ),where );
    403        }
    404
    405        /**
    406         * 【TAG】処理対象を特定するｷｰ条件(where句)をCSV形式で複数指定します｡
    407         *
    408         * @og.tag
    409         * 生成するQUERYのwhere 句を指定する方法として、複数のｶﾗﾑ名をCSV指定し、内部で
    410         * KEY=[KEY] 文字列を作成します｡
    411         * ここでは、ｶﾗﾑ名は、ﾃﾞｰﾀﾍﾞｰｽのｶﾗﾑ名と同じで、かつ、DBTableModel にも
    412         * 同じｶﾗﾑのﾃﾞｰﾀが存在していること、という条件付きとします｡
    413         * また、where 条件との併用を行いますが、こちらの条件が先に使用され、where 条件は、
    414         * and を付けて、文字列結合されます｡
    415         * 例： CLM,SYSTEM_ID,KBSAKU   ⇒   CLM=[CLM] and SYSTEM_ID=[SYSTEM_ID] and KBSAKU=[KBSAKU]
    416         *
    417         * @og.rev 5.5.8.5 (2012/11/27) 新規追加
    418         *
    419         * @param       wrnm    検索条件ｶﾗﾑ (where句)作成のためのｶﾗﾑ名(CSV形式)
    420         */
    421        public void setWhereNames( final String wrnm ) {
    422                whereNames = nval( getRequestParameter( wrnm ),whereNames );
    423        }
    424
    425        /**
    426         *【TAG】true に設定すると、sqlType="MERGE" 時のみ有効で、where 条件で存在すれば何もしない(初期値:false)｡
    427         *
    428         * @og.tag
    429         * true に設定すると、sqlType="MERGE" 時に、where条件で、検索して、存在しない場合は、追加します｡
    430         * 存在する場合は、何もしません｡
    431         * 何もしない（更新しない）ところが、通常のMERGEと異なる箇所です｡
    432         * 動作としては、UPDATEの代わりに、SELECT で判定します｡
    433         * 初期値は、false で、あれば更新、なければ追加処理を行います｡
    434         *
    435         * @og.rev 7.4.1.0 (2021/04/23) sqlType="MERGE" 時のみ有効で、where 条件で存在すれば何もしない
    436         *
    437         * @param       flag    "true" に設定すると、sqlType="MERGE" 時に、where条件で検索
    438         */
    439        public void setInsertOnly( final String flag ) {
    440                insertOnly = nval( getRequestParameter( flag ),insertOnly );
    441        }
    442
    443        /**
    444         * 【TAG】設定値を固定値と置き換える対象となるｶﾗﾑ名をCSV形式で複数指定します｡
    445         *
    446         * @og.tag
    447         * names 属性のｶﾗﾑや table 属性より、QUERYを作成して、DBTableModelの値を
    448         * 割り当てる場合、DBTableModelの値ではなく、外部から指定した固定値を
    449         * 割り当てたい場合に、そのｶﾗﾑ名をCSV形式(CSV)で複数指定します｡
    450         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します｡
    451         * こうしないとﾃﾞｰﾀ自身にｶﾝﾏを持っている場合に分解をﾐｽる為です｡
    452         *
    453         * @param       keys    固定値ｶﾗﾑ (CSV形式)
    454         * @see         #setConstVals( String )
    455         */
    456        public void setConstKeys( final String keys ) {
    457                constKeys = getCSVParameter( keys );
    458        }
    459
    460        /**
    461         * 【TAG】設定値を固定値と置き換える対象となる設定値をCSV形式で複数指定します｡
    462         *
    463         * @og.tag
    464         * names 属性のｶﾗﾑや table 属性より、QUERYを作成して、DBTableModelの
    465         * 値を割り当てる場合、DBTableModelの値ではなく、外部から指定した固定値を
    466         * 割り当てたい場合に、そのｶﾗﾑ名に対応する設定値をCSV形式(CSV)で
    467         * 複数指定します｡ここで指定する設定値は、constKeys 属性と対応させます｡
    468         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します｡
    469         * こうしないとﾃﾞｰﾀ自身にｶﾝﾏを持っている場合に分解をﾐｽる為です｡
    470         *
    471         * @param       vals    設定値(CSV形式)
    472         * @see         #setConstKeys( String )
    473         */
    474        public void setConstVals( final String vals ) {
    475                constVals = getCSVParameter( vals );
    476        }
    477
    478        /**
    479         * 【TAG】関数等を設定するｶﾗﾑ名をCSV形式で複数指定します｡
    480         *
    481         * @og.tag
    482         * constVals 属性で設定する値は、必ずｼﾝｸﾞﾙｸｵｰﾄが付与されます｡
    483         * その場合、関数などを設定したい場合でも、文字列として設定しようとします｡
    484         * ここで指定するｶﾗﾑ名(funcKeys)自身は、constKeys と同じ書式です｡
    485         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します｡
    486         * こうしないとﾃﾞｰﾀ自身にｶﾝﾏを持っている場合に分解をﾐｽる為です｡
    487         *
    488         * @og.rev 5.5.1.9 (2012/04/19) 新規追加
    489         *
    490         * @param       keys    関数ｶﾗﾑ (CSV形式)
    491         * @see         #setFuncVals( String )
    492         */
    493        public void setFuncKeys( final String keys ) {
    494                funcKeys = getCSVParameter( keys );
    495        }
    496
    497        /**
    498         * 【TAG】関数等の設定値をCSV形式で複数指定します｡
    499         *
    500         * @og.tag
    501         * funcKeys 属性に対応する 関数などの設定値を割り当てます｡
    502         * constVals 属性との違いは、funcVals の設定値は、そのままの形で、SQL文の
    503         * 構築に使われます｡
    504         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します｡
    505         * こうしないとﾃﾞｰﾀ自身にｶﾝﾏを持っている場合に分解をﾐｽる為です｡
    506         *
    507         * @og.rev 5.5.1.9 (2012/04/19) 新規追加
    508         *
    509         * @param       vals    関数設定値 (CSV形式)
    510         * @see         #setFuncKeys( String )
    511         */
    512        public void setFuncVals( final String vals ) {
    513                funcVals = getCSVParameter( vals );
    514        }
    515
    516        /**
    517         * 【TAG】別名を付けたｶﾗﾑ名(select A as B from TBL の B を指定)をCSV形式で複数指定します｡
    518         *
    519         * @og.tag
    520         * SELECT 文を記述したとき、別名を付けていたり、SELECTしたﾃｰﾌﾞﾙと別のﾃｰﾌﾞﾙに
    521         * DBTableModelの値を書き込む場合、DBTableModel の持っているｶﾗﾑ名と、実際に
    522         * 書き込むｶﾗﾑ名が異なります｡そのようなｹｰｽに、元の別名ｶﾗﾑを指定します｡
    523         * orgNames属性の並び順と、asNames属性の並び順を合わせておく必要があります｡
    524         * このｶﾗﾑ名は、DBTableModel には持っているが、ﾃｰﾌﾞﾙ側には持っていない値
    525         * なので、内部的に omitNames 属性に値を設定します｡利用者は、omitNames に
    526         * 書き込む必要はありません｡
    527         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します｡
    528         * こうしないとﾃﾞｰﾀ自身にｶﾝﾏを持っている場合に分解をﾐｽる為です｡
    529         *
    530         * @og.rev 5.5.1.9 (2012/04/19) 新規追加
    531         *
    532         * @param       keys    別名ｶﾗﾑ (CSV形式)
    533         * @see         #setOrgNames( String )
    534         */
    535        public void setAsNames( final String keys ) {
    536                asNames = getCSVParameter( keys );
    537        }
    538
    539        /**
    540         * 【TAG】tableの実際のｶﾗﾑ名(select A as B from TBL の A を指定)をCSV形式で複数指定します｡
    541         *
    542         * @og.tag
    543         * SELECT 文を記述したとき、別名を付けていたり、SELECTしたﾃｰﾌﾞﾙと別のﾃｰﾌﾞﾙに
    544         * DBTableModelの値を書き込む場合、DBTableModel の持っているｶﾗﾑ名と、実際に
    545         * 書き込むｶﾗﾑ名が異なります｡そのようなｹｰｽに、ﾃｰﾌﾞﾙの実ｶﾗﾑを指定します｡
    546         * orgNames属性の並び順と、asNames属性の並び順を合わせておく必要があります｡
    547         * このｶﾗﾑ名は、DBTableModel には持っていませんが、ﾃｰﾌﾞﾙ側には持っている値
    548         * なので、このｶﾗﾑ名で、SQL文を構築します｡ UPDATE TBL SET A=[B] WHERE … となります｡
    549         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します｡
    550         * こうしないとﾃﾞｰﾀ自身にｶﾝﾏを持っている場合に分解をﾐｽる為です｡
    551         *
    552         * @og.rev 5.5.1.9 (2012/04/19) 新規追加
    553         *
    554         * @param       keys    実ｶﾗﾑ (CSV形式)
    555         * @see         #setAsNames( String )
    556         */
    557        public void setOrgNames( final String keys ) {
    558                orgNames = getCSVParameter( keys );
    559        }
    560
    561        /**
    562         * 【TAG】ﾘｸｴｽﾄ情報の ｼﾝｸﾞﾙｸｫｰﾄ(') 存在ﾁｪｯｸを実施するかどうか[true/false]を設定します
    563         *              (初期値:USE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])｡
    564         *
    565         * @og.tag
    566         * SQLｲﾝｼﾞｪｸｼｮﾝ対策の一つとして、暫定的ではありますが、SQLのﾊﾟﾗﾒｰﾀに
    567         * 渡す文字列にｼﾝｸﾞﾙｸｫｰﾄ(') を許さない設定にすれば、ある程度は防止できます｡
    568         * 数字ﾀｲﾌﾟの引数には、 or 5=5 などのｼﾝｸﾞﾙｸｫｰﾄを使用しないｺｰﾄﾞを埋めても、
    569         * 数字ﾁｪｯｸで検出可能です｡文字ﾀｲﾌﾟの場合は、必ず (')をはずして、
    570         * ' or 'A' like 'A のような形式になる為、(')ﾁｪｯｸだけでも有効です｡
    571         * (') が含まれていたｴﾗｰにする(true)/かﾉｰﾁｪｯｸか(false)を指定します｡
    572         * (初期値:ｼｽﾃﾑ定数のUSE_SQL_INJECTION_CHECK[={@og.value SystemData#USE_SQL_INJECTION_CHECK}])｡
    573         *
    574         * @param       flag    ｸｫｰﾄﾁｪｯｸ [true:する/それ以外:しない]
    575         * @see         org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK
    576         */
    577        public void setQuotCheck( final String flag ) {
    578                quotCheck = nval( getRequestParameter( flag ),quotCheck );
    579        }
    580
    581        /**
    582         * 【TAG】固定情報ｶﾗﾑの処理ｵﾌﾞｼﾞｪｸﾄを特定するｷｰを設定します(初期値:SYSTEM_ID)｡
    583         *
    584         * @og.tag
    585         * 固定情報ｶﾗﾑ をｼｽﾃﾑ単位にJavaｸﾗｽで管理できます｡
    586         * そのｸﾗｽｵﾌﾞｼﾞｪｸﾄは、org.opengion.hayabusa.db.DBConstValue ｲﾝﾀｰﾌｪｰｽを
    587         * 継承した、plugin ｸﾗｽになります｡
    588         * そのｸﾗｽを特定するｷｰﾜｰﾄﾞを指定します｡
    589         * 初期値は、SYSTEM_ID でｼｽﾃﾑ単位にｸﾗｽを作成します｡
    590         * もし、他のｼｽﾃﾑと共通の場合は、継承だけさせることも可能です｡
    591         * 対応したDBConstValueｸﾗｽがﾌﾟﾗｸﾞｲﾝとして存在しない場合は、
    592         * ｼｽﾃﾑﾘｿｰｽのDEFAULT_CONST_CLASSで指定されたｸﾗｽが利用されます｡
    593         * 固定情報ｶﾗﾑを使用しない場合は、constObjKey="" をｾｯﾄしてください｡
    594         *
    595         * 初期値は、SYSTEM_ID です｡
    596         *
    597         * @og.rev 6.9.8.0 (2018/05/28) 固定情報ｶﾗﾑを使用しない場合は、constObjKey="" をｾｯﾄ｡
    598         *
    599         * @param       key     固定ｶﾗﾑｷｰ
    600         */
    601        public void setConstObjKey( final String key ) {
    602//              constObjKey = nval( getRequestParameter( key ),constObjKey );
    603                final String objKey = getRequestParameter( key );
    604                if( objKey != null ) { constObjKey = objKey; }
    605        }
    606
    607        /**
    608         * 【TAG】sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します(初期値:false)｡
    609         *
    610         * @og.tag
    611         * sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します｡
    612         * trueが指定された場合は、DELETE文ではなく、UPDATE文が発行されます｡
    613         * falseが指定された場合は、DELETE文が発行されます｡
    614         * さらに論理削除を行う場合、org.opengion.hayabusa.db.DBConstValue ｲﾝﾀｰﾌｪｰｽに
    615         * 定義されている、getLogicalDeleteKeys()及びgetLogicalDeleteValsを実装することで、
    616         * 論理削除する際のﾌﾗｸﾞの更新方法を統一的に管理することが可能になります｡
    617         * 初期値は、false(物理削除する)です
    618         *
    619         * @param       flag    論理削除可否 [true:UPDATE文/false:DELETE文]
    620         */
    621        public void setLogicalDelete( final String flag ) {
    622                logicalDelete = nval( getRequestParameter( flag ),logicalDelete );
    623        }
    624
    625        /**
    626         * ﾃﾞｰﾀをｲﾝｻｰﾄする場合に使用するSQL文を作成します｡
    627         *
    628         * @og.rev 4.1.2.1 (2008/03/17) DBConstValue による固定値ｾｯﾄを採用
    629         * @og.rev 4.3.6.4 (2009/05/01) ﾃﾞﾌｫﾙﾄ設定をｼｽﾃﾑﾘｿｰｽで設定可能にする
    630         * @og.rev 5.3.4.0 (2011/04/01) DEFAULT_CONST_OBJの初期値変更(null→ｾﾞﾛ文字列)
    631         * @og.rev 6.2.3.0 (2015/05/01) CSV形式の作成を、String#join( CharSequence , CharSequence... )を使用｡
    632         *
    633         * @param       namesData       NamesDataｵﾌﾞｼﾞｪｸﾄ
    634         *
    635         * @return      ｲﾝｻｰﾄSQL
    636         * @og.rtnNotNull
    637         */
    638        private String getInsertSQL( final NamesData namesData ) {
    639                String cls = HybsSystem.sys( "DBConstValue_" + constObjKey ) ;
    640
    641                // 4.3.6.4 (2009/05/01) 標準の追加
    642                if( cls == null){
    643                        cls = DEFAULT_CONST_OBJ;
    644                }
    645
    646                if( cls != null && !cls.isEmpty() ) {
    647                        final DBConstValue constVal = HybsSystem.newInstance( cls );
    648                        // 4.2.1.0 (2008/04/16) 初期化追加
    649                        constVal.init( table,getUser().getUserID(),getGUIInfoAttri( "KEY" ) );
    650                        final String[] keys = constVal.getInsertKeys();
    651                        final String[] vals = constVal.getInsertVals();
    652                        namesData.add( keys,vals );
    653                }
    654
    655                final String[] nms = namesData.getNames();
    656                final String[] vls = namesData.getVals();
    657
    658                // 6.2.3.0 (2015/05/01) CSV形式の作成を、String#join( CharSequence , CharSequence... )を使用。
    659                final StringBuilder sql = new StringBuilder( BUFFER_MIDDLE )
    660                        .append( "INSERT INTO " ).append( table )
    661                        .append( " ( " )
    662                        .append( String.join( "," , nms ) )             // 6.2.3.0 (2015/05/01)
    663                        .append( " ) VALUES ( " )
    664                        .append( String.join( "," , vls ) )             // 6.2.3.0 (2015/05/01)
    665                        .append( " )" );
    666
    667                return sql.toString();
    668        }
    669
    670        /**
    671         * ﾃﾞｰﾀをｱｯﾌﾟﾃﾞｰﾄする場合に使用するSQL文を作成します｡
    672         *
    673         * where と whereNames が同時に指定された場合は、whereNames が先に処理され
    674         * where 条件は、and 結合されます｡
    675         *
    676         * @og.rev 4.1.2.1 (2008/03/17) DBConstValue による固定値ｾｯﾄを採用
    677         * @og.rev 4.3.6.4 (2009/05/01) ﾃﾞﾌｫﾙﾄ設定をｼｽﾃﾑﾘｿｰｽで設定可能にする
    678         * @og.rev 4.3.7.0 (2009/06/01) 論理削除対応
    679         * @og.rev 5.3.7.0 (2011/07/01) DEFAULT_CONST_OBJの初期値変更(null→ｾﾞﾛ文字列) 対応忘れ
    680         * @og.rev 5.5.8.5 (2012/11/27) whereNames 対応
    681         *
    682         * @param       namesData       NamesDataｵﾌﾞｼﾞｪｸﾄ
    683         *
    684         * @return      ｱｯﾌﾟﾃﾞｰﾄSQL
    685         * @og.rtnNotNull
    686         */
    687        private String getUpdateSQL( final NamesData namesData ) {
    688                String cls = HybsSystem.sys( "DBConstValue_" + constObjKey ) ;
    689
    690                // 4.3.6.4 (2009/05/01) 標準の追加
    691                if( cls == null){
    692                        cls = DEFAULT_CONST_OBJ;
    693                }
    694
    695                if( cls != null && !cls.isEmpty() ) {           // 5.3.7.0 (2011/07/01)
    696                        final DBConstValue constVal = HybsSystem.newInstance( cls );
    697                        // 4.2.1.0 (2008/04/16) 初期化追加
    698                        constVal.init( table,getUser().getUserID(),getGUIInfoAttri( "KEY" ) );
    699                        // 4.3.7.0 (2009/06/01) 論理削除対応
    700                        String[] keys = null;
    701                        String[] vals = null;
    702                        if( "DELETE".equalsIgnoreCase( sqlType ) ) {
    703                                keys = constVal.getLogicalDeleteKeys();
    704                                vals = constVal.getLogicalDeleteVals();
    705                        }
    706                        else {
    707                                keys = constVal.getUpdateKeys();
    708                                vals = constVal.getUpdateVals();
    709                        }
    710                        namesData.add( keys,vals );
    711                }
    712
    713                final String[] nms = namesData.getNames();
    714                final String[] vls = namesData.getVals();
    715
    716                final StringBuilder sql = new StringBuilder( BUFFER_MIDDLE )
    717                        .append( "UPDATE " ).append( table ).append( " SET " )
    718                        .append( nms[0] ).append( '=' ).append( vls[0] );                                       // 6.0.2.5 (2014/10/31) char を append する。
    719
    720                for( int i=1; i<nms.length; i++ ) {
    721                        sql.append( ',' ).append( nms[i] ).append( '=' ).append( vls[i] );      // 6.0.2.5 (2014/10/31) char を append する。
    722                }
    723
    724                // 5.5.8.5 (2012/11/27) whereNames 対応
    725                String whereAnd = " WHERE " ;
    726                if( whereNames != null && whereNames.length() > 0 ) {
    727                        final String[] wnms = whereNames.split(",");
    728                        sql.append( whereAnd ).append( wnms[0] ).append( "=[" ).append( wnms[0] ).append( ']' );        // 6.0.2.5 (2014/10/31) char を append する。
    729
    730                        for( int i=1; i<wnms.length; i++ ) {
    731                                sql.append( " AND " ).append( wnms[i] ).append( "=[" ).append( wnms[i] ).append( ']' ); // 6.0.2.5 (2014/10/31) char を append する。
    732                        }
    733                        whereAnd = " AND " ;            // whereNames 優先。ここを通らなければ、初期値のまま、" WHERE " が使われる
    734                }
    735
    736                // 5.5.8.5 (2012/11/27) whereNames 対応。whereNames が登録されていれば、AND で繋げる。
    737                if( where != null && where.length() > 0 ) {
    738                        sql.append( whereAnd ).append( where );
    739                }
    740
    741                return sql.toString();
    742        }
    743
    744        /**
    745         * ﾃﾞｰﾀをﾃﾞﾘｰﾄする場合に使用するSQL文を作成します｡
    746         *
    747         * where と whereNames が同時に指定された場合は、whereNames が先に処理され
    748         * where 条件は、and 結合されます｡
    749         *
    750         * @og.rev 5.5.8.5 (2012/11/27) whereNames 対応
    751         *
    752         * @return      ﾃﾞﾘｰﾄSQL
    753         * @og.rtnNotNull
    754         */
    755        private String getDeleteSQL() {
    756                final StringBuilder sql = new StringBuilder( BUFFER_MIDDLE );
    757                sql.append( "DELETE FROM " ).append( table );
    758
    759                // 5.5.8.5 (2012/11/27) whereNames 対応
    760                String whereAnd = " WHERE " ;
    761                if( whereNames != null && whereNames.length() > 0 ) {
    762                        final String[] wnms = whereNames.split(",");
    763                        sql.append( whereAnd ).append( wnms[0] ).append( "=[" ).append( wnms[0] ).append( ']' );        // 6.0.2.5 (2014/10/31) char を append する。
    764
    765                        for( int i=1; i<wnms.length; i++ ) {
    766                                sql.append( " AND " ).append( wnms[i] ).append( "=[" ).append( wnms[i] ).append( ']' ); // 6.0.2.5 (2014/10/31) char を append する。
    767                        }
    768                        whereAnd = " AND " ;            // whereNames 優先。ここを通らなければ、初期値のまま、" WHERE " が使われる
    769                }
    770
    771                // 5.5.8.5 (2012/11/27) whereNames 対応。whereNames が登録されていれば、AND で繋げる。
    772                if( where != null && where.length() > 0 ) {
    773                        sql.append( whereAnd ).append( where );
    774                }
    775                return sql.toString();
    776        }
    777
    778        /**
    779         * ﾃﾞｰﾀを検索する場合に使用するSQL文を作成します｡
    780         *
    781         * where と whereNames が同時に指定された場合は、whereNames が先に処理され
    782         * where 条件は、and 結合されます｡
    783         *
    784         * これは、sqlType="MERGE" 時に、insertOnly="true" が指定された時に、呼ばれます｡
    785         *
    786         * @og.rev 7.4.1.0 (2021/04/23) sqlType="MERGE" 時のみ有効で、where 条件で存在すれば何もしない
    787         *
    788         * @return      検索SQL
    789         * @og.rtnNotNull
    790         */
    791        private String getSelectSQL() {
    792                final StringBuilder sql = new StringBuilder( BUFFER_MIDDLE );
    793                sql.append( "SELECT count(*) FROM " ).append( table );
    794
    795                // 5.5.8.5 (2012/11/27) whereNames 対応
    796                String whereAnd = " WHERE " ;
    797                if( whereNames != null && whereNames.length() > 0 ) {
    798                        final String[] wnms = whereNames.split(",");
    799                        sql.append( whereAnd ).append( wnms[0] ).append( "=[" ).append( wnms[0] ).append( ']' );        // 6.0.2.5 (2014/10/31) char を append する。
    800
    801                        for( int i=1; i<wnms.length; i++ ) {
    802                                sql.append( " AND " ).append( wnms[i] ).append( "=[" ).append( wnms[i] ).append( ']' ); // 6.0.2.5 (2014/10/31) char を append する。
    803                        }
    804                        whereAnd = " AND " ;            // whereNames 優先。ここを通らなければ、初期値のまま、" WHERE " が使われる
    805                }
    806
    807                // 5.5.8.5 (2012/11/27) whereNames 対応。whereNames が登録されていれば、AND で繋げる。
    808                if( where != null && where.length() > 0 ) {
    809                        sql.append( whereAnd ).append( where );
    810                }
    811                return sql.toString();
    812        }
    813
    814        /**
    815         * names,constKeys,omitNames から、必要なｷｰ情報と、属性情報を持った NamesData を作成します｡
    816         *
    817         * @og.rev 4.1.2.1 (2008/03/17) 固定値の constVals の前後に、"'" を入れる｡
    818         * @og.rev 5.5.1.9 (2012/04/19) asNames、orgNames、funcKeys、funcVals属性追加
    819         *
    820         * @param       nms     ｶﾗﾑ名配列(可変長引数)
    821         *
    822         * @return      属性情報を持ったNamesData
    823         */
    824        private NamesData makeNamesData( final String... nms ) {
    825                final NamesData namesData = new NamesData();
    826
    827                // 5.5.1.9 (2012/04/19) omitNames に、asNames配列の値を設定しておきます。
    828                if( asNames != null ) {
    829                        for( int i=0; i<asNames.length; i++ ) {
    830                                if( asNames[i] != null && asNames[i].length() > 0 ) {
    831                                        omitNames = omitNames + asNames[i] + ",";
    832                                }
    833                        }
    834                }
    835
    836                // names で指定されたｶﾗﾑ名
    837                for( int i=0; i<nms.length; i++ ) {
    838                        final String nm = nms[i];
    839                        if( nm != null && nm.length() > 0 && omitNames.indexOf( "," + nm + "," ) < 0 ) {
    840                                namesData.add( nm,"[" + nm + "]" ) ;
    841                        }
    842                }
    843
    844                // 固定値の constKeys ｶﾗﾑ配列を設定します｡
    845                if( constKeys != null && constKeys.length > 0 ) {
    846                        for( int j=0; j<constKeys.length; j++ ) {
    847                                final String nm = constKeys[j];
    848                                if( nm != null && nm.length() > 0 ) {
    849                                        namesData.add( nm,"'" + constVals[j] + "'" ) ;  // constVals は、シングルクオートで囲います。
    850                                }
    851                        }
    852                }
    853
    854                // 関数値の funcKeys ｶﾗﾑ配列を設定します｡
    855                if( funcKeys != null && funcKeys.length > 0 ) {
    856                        for( int j=0; j<funcKeys.length; j++ ) {
    857                                final String nm = funcKeys[j];
    858                                if( nm != null && nm.length() > 0 ) {
    859                                        namesData.add( nm, funcVals[j] ) ;              // funcVals は、シングルクオートで囲いません。
    860                                }
    861                        }
    862                }
    863
    864                // 別名の asNames,orgNames ｶﾗﾑ配列を設定します｡
    865                if( orgNames != null && orgNames.length > 0 ) {
    866                        for( int j=0; j<orgNames.length; j++ ) {
    867                                final String onm = orgNames[j];
    868                                if( onm != null && onm.length() > 0 ) {
    869                                        namesData.add( onm,"[" + asNames[j] + "]" ) ;
    870                                }
    871                        }
    872                }
    873
    874                return namesData ;
    875        }
    876
    877        /**
    878         * 内部ﾃﾞｰﾀを受け渡す為の、簡易ｸﾗｽです｡
    879         * 更新するｶﾗﾑ名と値のｾｯﾄ配列を管理しています｡
    880         *
    881         * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更｡
    882         *    ※ classのfinal化と変数のprivate化、ﾒｿｯﾄﾞの修飾子なし(ﾊﾟｯｹｰｼﾞﾌﾟﾗｲﾍﾞｰﾄ)化を行います｡
    883         * @og.rev 6.4.1.2 (2016/01/22) nameの値を、大文字小文字の区別をなくすために、常に大文字で登録します｡
    884         */
    885        private static final class NamesData {
    886                private final Map<String,String> nameMap = new LinkedHashMap<>() ;
    887
    888                /**
    889                 * 内部のMapをｺﾋﾟｰした新しいｲﾝｽﾀﾝｽを返します｡
    890                 *
    891                 * @og.rev 8.3.0.3 (2022/08/26) sqlType="MERGE" の場合、UPDATE文 に追加関連固定ｶﾗﾑｷｰが追加される不具合対応
    892                 *
    893                 * @return      新しいｲﾝｽﾀﾝｽ
    894                 */
    895                /* default */ NamesData newInstance () {
    896                        final NamesData newNames = new NamesData();
    897                        newNames.nameMap.putAll( nameMap );
    898                        return newNames;
    899                }
    900
    901                /**
    902                 * ｷｰと値のｾｯﾄを追加します｡
    903                 *
    904                 * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更｡
    905                 * @og.rev 6.4.1.2 (2016/01/22) nameの値を、大文字小文字の区別をなくすために、常に大文字で登録します｡
    906                 *
    907                 * @param       nm      ｷｰ（大文字のみ｡内部で変換しておきます｡）
    908                 * @param       val     値
    909                 */
    910                /* default */ void add( final String nm,final String val ) {
    911                        nameMap.put( nm.toUpperCase(Locale.JAPAN),val );
    912                }
    913
    914                /**
    915                 * ｷｰ配列と対応する、値配列のｾｯﾄを追加します｡
    916                 *
    917                 * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更｡
    918                 *
    919                 * @param       nms             ｷｰ配列
    920                 * @param       vals    値配列
    921                 */
    922                /* default */ void add( final String[] nms,final String[] vals ) {
    923                        if( nms != null ) {
    924                                for( int i=0; i<nms.length; i++ ) {
    925                                        nameMap.put( nms[i].toUpperCase(Locale.JAPAN),vals[i] );
    926                                }
    927                        }
    928                }
    929
    930                /**
    931                 * ｷｰ配列を返します｡
    932                 *
    933                 * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更｡
    934                 *
    935                 * @return      ｷｰ配列
    936                 * @og.rtnNotNull
    937                 */
    938                /* default */ String[] getNames() {
    939                        return nameMap.keySet().toArray( new String[nameMap.size()] );
    940                }
    941
    942                /**
    943                 * 値配列を返します｡
    944                 *
    945                 * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private に変更｡
    946                 *
    947                 * @return      値配列
    948                 * @og.rtnNotNull
    949                 */
    950                /* default */ String[] getVals()  {
    951                        return nameMap.values().toArray( new String[nameMap.size()] );
    952                }
    953        }
    954
    955        /**
    956         * このｵﾌﾞｼﾞｪｸﾄの文字列表現を返します｡
    957         * 基本的にﾃﾞﾊﾞｯｸﾞ目的に使用します｡
    958         *
    959         * @return      このｸﾗｽの文字列表現
    960         * @og.rtnNotNull
    961         */
    962        @Override
    963        public String toString() {
    964                return ToString.title( this.getClass().getName() )
    965                                .println( "VERSION"                     ,VERSION                )
    966                                .println( "sqlType"                     ,sqlType                )
    967                                .println( "table"                       ,table                  )
    968                                .println( "names"                       ,names                  )
    969                                .println( "omitNames"           ,omitNames              )
    970                                .println( "where"                       ,where                  )
    971                                .println( "whereNames"          ,whereNames             )
    972                                .println( "constKeys"           ,constKeys              )
    973                                .println( "constVals"           ,constVals              )
    974                                .println( "logicalDelete"       ,logicalDelete  )
    975                                .fixForm().toString() ;
    976        }
    977}