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.fukurou.business;
017
018import java.sql.Connection;
019import java.sql.ParameterMetaData;
020import java.sql.PreparedStatement;
021import java.sql.ResultSet;
022import java.sql.ResultSetMetaData;
023import java.sql.SQLException;
024import java.util.Map;
025import java.util.HashMap;                                                                                                               // 6.4.3.3 (2016/03/04) not null調査が済むまで、元に戻します。
026import java.util.concurrent.ConcurrentMap;                                                                              // 6.4.3.3 (2016/03/04)
027import java.util.concurrent.ConcurrentHashMap;                                                                  // 6.4.3.1 (2016/02/12) refactoring
028import java.util.Locale;
029import java.util.Set;
030import java.util.Arrays;
031import java.util.function.Consumer;                                                                                             // 8.2.0.3 (2022/06/30)
032
033import org.opengion.fukurou.system.OgRuntimeException ;                                                 // 6.4.2.0 (2016/01/29)
034import org.opengion.fukurou.db.ConnectionFactory;
035import org.opengion.fukurou.db.DBFunctionName;
036import org.opengion.fukurou.db.DBUtil;
037import org.opengion.fukurou.db.ResultSetValue;                                                                  // 8.2.0.3 (2022/06/30)
038import org.opengion.fukurou.db.Transaction;
039import org.opengion.fukurou.model.Formatter;
040import org.opengion.fukurou.model.DataModel;                                                                    // 6.7.9.1 (2017/05/19)
041import org.opengion.fukurou.system.DateSet;                                                                             // 6.4.2.0 (2016/01/29)
042import org.opengion.fukurou.util.ErrMsg;
043import org.opengion.fukurou.util.ErrorMessage;
044import org.opengion.fukurou.util.HybsLoader;
045import org.opengion.fukurou.util.StringUtil;
046import org.opengion.fukurou.util.SystemParameter;
047import static org.opengion.fukurou.system.HybsConst.CR;                                                 // 6.1.0.0 (2014/12/26) refactoring
048import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;                              // 6.1.0.0 (2014/12/26) refactoring
049import static org.opengion.fukurou.system.HybsConst.DB_FETCH_SIZE;                              // 6.9.4.1 (2018/04/09)
050
051/**
052 * 業務ロジックを処理するために必要な共通メソッドの実行を行っている抽象クラスです。
053 *
054 * メインロジックについては、各サブクラスで実装する必要があります。
055 *
056 * @og.rev 5.1.1.0 (2009/12/01) 新規作成
057 * @og.group 業務ロジック
058 *
059 * @version 5.0
060 * @author Hiroki Nakamura
061 * @since JDK1.6,
062 */
063public abstract class AbstractBizLogic {
064
065        /** エラーメッセージをセットする際に使用します {@value} */
066        protected static final int OK        = ErrorMessage.OK;
067        /** エラーメッセージをセットする際に使用します {@value} */
068        protected static final int WARNING   = ErrorMessage.WARNING;
069        /** エラーメッセージをセットする際に使用します {@value} */
070        protected static final int NG        = ErrorMessage.NG;
071        /** エラーメッセージをセットする際に使用します {@value} */
072        protected static final int EXCEPTION = ErrorMessage.EXCEPTION;
073        /** エラーメッセージをセットする際に使用します {@value} */
074        protected static final int ORCL_ERR  = ErrorMessage.ORCL_ERR;
075
076//      /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ  {@value} */
077//      private static final int DB_FETCH_SIZE = 1001 ;
078
079        private Connection      conn    ;
080        private Transaction tran        ;                       // 5.1.9.0 (2010/08/01) シーケンス対応
081        private String          dbid    ;                       // 5.1.9.0 (2010/08/01) シーケンス対応
082        /** データベースファンクション */
083        protected DBFunctionName        dbName  ;       // 5.1.9.0 (2010/08/01) シーケンス対応
084        private HybsLoader      loader  ;
085        private String[]        keys    ;
086        private String[]        vals    ;
087        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
088        private final Map<String, String> variableMap  = new HashMap<>();                                                               // 6.4.3.3 (2016/03/04) not null調査が済むまで、元に戻します。
089        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
090        private final ConcurrentMap<String, Formatter> formatMap = new ConcurrentHashMap<>();
091        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
092        private final ConcurrentMap<String, SystemParameter> sysParamMap = new ConcurrentHashMap<>();
093        private final ErrorMessage errMsg = new ErrorMessage();
094        private String bizRtn           ;                                       // 5.1.8.0 (2010/07/01) メソッド名と変数名を分ける。
095        private boolean debugFlag       ;                                       // 5.1.8.0 (2010/07/01) メソッド名と変数名を分ける。
096
097        private final StringBuilder debugMsg = new StringBuilder( BUFFER_MIDDLE );
098        private boolean useParamMetaData        ;                       // 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)
099
100        private final ConcurrentMap<String, String> rtnMap = new ConcurrentHashMap<>();         // 6.9.9.0 (2018/08/20) 戻り値を返せるようにします。
101
102        /**
103         * 配列側テーブルモデル
104         *
105         * 配列型テーブルモデル自体は、protected属性であるため、サブクラスから直接参照することができます。
106         * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの
107         * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。
108         * (この想定がなければ、本来は、package privateにすべきです)
109         * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。
110         *
111         * @og.rev 6.7.9.1 (2017/05/19) protected ArrayTableModel を、private DataModel に変更します。
112         */
113        private DataModel<String> table ;                               // 6.7.9.1 (2017/05/19)
114
115        /**
116         * 配列型テーブルモデルの現在の処理行
117         *
118         * 行番号自体は、protected属性であるため、サブクラスから直接参照することができます。
119         * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの
120         * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。
121         * (この想定がなければ、本来は、package privateにすべきです)
122         * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。
123         *
124         * ※ インデックス(row)とは、このArrayTableModel に持つ vals 配列の行のインデックスです。
125         * よって、オリジナルのDBTableModelの行番号ではありません。
126         *
127         * @og.rev 8.0.2.0 (2021/11/30) protected → default 変更(サブクラスからのアクセスはない)
128         */
129//      protected int row = -1;
130        /* default */ int row = -1;
131
132        /**
133         * デフォルトコンストラクター
134         *
135         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
136         */
137        protected AbstractBizLogic() { super(); }               // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
138
139        /**
140         * DBのトランザクションオブジェクトを指定します。
141         * 各実装クラスでは、コネクションのcommit,rollbackは行われません。
142         * (全てのDB処理は、1つのトランザクションとして処理されます。)
143         * このため、commit,rollbackは呼び出し元で行う必要があります。
144         * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。
145         *
146         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
147         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)
148         * @og.rev 8.0.2.0 (2021/11/30) protected → default 変更(サブクラスからのアクセスはない)
149         *
150         * @param       tr      トランザクション
151         */
152//      public void setTransaction( final Transaction tr ) {
153        /* default */ void setTransaction( final Transaction tr ) {
154                tran = tr;
155                conn = tran.getConnection( dbid );
156                useParamMetaData = ConnectionFactory.useParameterMetaData( dbid );      // 5.3.8.0 (2011/08/01)
157        }
158
159        /**
160         * DBのトランザクションオブジェクトを返します。
161         *
162         * (全てのDB処理は、1つのトランザクションとして処理されます。)
163         *
164         * @og.rev 7.4.2.0 (2021/05/14) 外部から指定するTransactionオブジェクト 対応
165         * @og.rev 8.0.2.0 (2021/11/30) protected → default 変更(サブクラスからのアクセスはない)
166         * @og.rev 8.1.1.0 (2022/02/04) default ⇒ protected に変更します。
167         *
168         * @return      トランザクション
169         */
170//      public Transaction getTransaction() {
171        protected Transaction getTransaction() {
172                return tran;
173        }
174
175        /**
176         * 接続先IDを指定します。
177         * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。
178         *
179         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
180         *
181         * @param       id      接続先ID
182         */
183        /* default */ void setDbid( final String id ) {
184                dbid = id;
185        }
186
187        /**
188         * 業務ロジックのクラスをロードするためのクラスローダーをセットします。
189         * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。
190         *
191         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
192         *
193         * @param       ldr     クラスローダー
194         */
195        /* default */ void setLoader( final HybsLoader ldr ) {
196                if( loader != null ) {
197                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
198                        final String errMsg = "既にクラスローダーがセットされています。"
199                                                                        + " OLD:" + loader
200                                                                        + " IN :" + ldr ;
201                        throw new OgRuntimeException( errMsg );
202                }
203                loader = ldr;
204        }
205
206        /**
207         * 配列型テーブルモデルをセットします。
208         * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。
209         *
210         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
211         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
212         *
213         * @param       tbl     配列型テーブルモデル
214         */
215        /* default */ void setTable( final DataModel<String> tbl ) {
216                if( table != null ) {
217                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
218                        final String errMsg = "既に配列型テーブルモデルがセットされています。"
219                                                                + " OLD:" + table
220                                                                + " IN :" + tbl ;
221                        throw new OgRuntimeException( errMsg );
222                }
223                table = tbl;
224        }
225
226        /**
227         * 配列型テーブルモデルを取得します。
228         *
229         * @og.rev 6.7.9.1 (2017/05/19) 新規追加
230         *
231         * @return 配列型テーブルモデル
232         */
233        protected DataModel<String> getTable() {
234                return table ;
235        }
236
237        /**
238         * 固定値のキー配列を指定します。
239         * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。
240         *
241         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
242         *
243         * @param       ks      キー配列(可変長引数)
244         */
245        /* default */ void setKeys( final String... ks ) {
246                if( keys != null ) {
247                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
248                        final String errMsg = "既に固定値配列(キー)がセットされています。"  + CR
249                                                        + "   KESY   =" + Arrays.toString( keys )                       + CR
250                                                        + "   in keys=" + Arrays.toString( ks ) ;
251                        throw new OgRuntimeException( errMsg );
252                }
253                if( ks != null && ks.length > 0 ) { keys = ks; }                // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
254        }
255
256        /**
257         * 固定値の値配列を指定します。
258         * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。
259         *
260         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
261         *
262         * @param       vs      値配列(可変長引数)
263         */
264        /* default */ void setVals( final String... vs ) {
265                if( vals != null ) {
266                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
267                        final String errMsg = "既に固定値配列(値)がセットされています。"   + CR
268                                                        + "   VALS   =" + Arrays.toString( vals )               + CR
269                                                        + "   in vals=" + Arrays.toString( vs ) ;
270                        throw new OgRuntimeException( errMsg );
271                }
272                if( vs != null && vs.length > 0 ) { vals = vs; }                // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
273        }
274
275        /**
276         * この処理の実行ユーザーIDを指定します。
277         *
278         * @param       id      実行ユーザーID(not null)
279         */
280        /* default */ void setUserId( final String id ) {
281                variableMap.put( "CON.USERID", id);
282        }
283
284        /**
285         * 親(呼び出し)PGIDを指定します。
286         *
287         * @param       id      親PGID
288         */
289        /* default */ void setParentPgId( final String id ) {
290                variableMap.put( "CON.PGPID", id );
291        }
292
293        /**
294         * デバッグモードにします。
295         */
296        /* default */ void setDebug() {
297                debugFlag = true;
298        }
299
300        /**
301         * デバッグメッセージを取得します。
302         *
303         * @return      デバッグメッセージ
304         * @og.rtnNotNull
305         */
306        /* default */ String getDebugMsg() {
307                return debugMsg.toString();
308        }
309
310        /**
311         * 処理を実行します。
312         * 処理の方法は、main()メソッドにより定義されます。
313         * 実装クラスで発生した全ての例外は、Throwableオブジェクトとしてスローされます。
314         * 呼び出し元では、例外を確実にcatchして、commit,rollbackを行ってください。
315         *
316         * @og.rev 5.1.9.0 (2010/08/01) シーケンス対応
317         *
318         * @return      処理が成功したかどうか
319         * @throws      Throwable 実行時の全エラーを上位に転送します。
320         */
321        /* default */ boolean exec() throws Throwable {
322                dbName = DBFunctionName.getDBName( ConnectionFactory.getDBName( dbid ) );
323                makeParamMap();
324                init();
325
326                return main();
327        }
328
329        /**
330         * 処理のメインロジックの前処理を記述します。
331         *
332         * このメソッド自体は、protected属性であるため、サブクラスから直接参照することができます。
333         * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの
334         * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。
335         * (この想定がなければ、本来は、package privateにすべきです)
336         * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。
337         */
338        protected abstract void init();
339
340        /**
341         * 処理のメインロジックを記述します。
342         *
343         * このメソッド自体は、protected属性であるため、サブクラスから直接参照することができます。
344         * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの
345         * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。
346         * (この想定がなければ、本来は、package privateにすべきです)
347         * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。
348         *
349         * @return      処理が正常終了したか
350         */
351        protected abstract boolean main();
352
353        /**
354         * 結果ステータスを返します。
355         *
356         * @return      結果ステータス
357         */
358        /* default */ int getKekka() {
359                return errMsg.getKekka();
360        }
361
362        /**
363         * エラーメッセージオブジェクトを返します。
364         *
365         * @return      エラーメッセージ
366         */
367        /* default */ ErrorMessage getErrMsg() {
368                return errMsg;
369        }
370
371        /**
372         * 業務ロジックの戻り値を返します。
373         *
374         * @return      戻り値
375         */
376        /* default */ String getReturn() {
377                return bizRtn;
378        }
379
380        /**
381         * 業務ロジックを実行するために、テーブルモデルが外部からセットされる必要があるか
382         * を返します。
383         * 必須である場合、その業務ロジックは、子ロジックとして呼び出すことができません。
384         * これは、子ロジック呼び出し時は、テーブルモデルがセットされないためです。
385         * (このクラスは、テーブルモデルが外部から指定されている必要はありません。)
386         *
387         * このメソッド自体は、protected属性であるため、サブクラスから直接参照することができます。
388         * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの
389         * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。
390         * (この想定がなければ、本来は、package privateにすべきです)
391         * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。
392         *
393         * @og.rev 8.0.2.0 (2021/11/30) protected → default 変更(サブクラスからのアクセスはない)
394         *
395         * @return      テーブルモデルが外部からセットされる必要があるかどうか(常にfalse)
396         */
397//      protected boolean isRequireTable() {
398        /* default */ boolean isRequireTable() {
399                return false;
400        }
401
402        /**
403         * デバッグモードかどうかを返します。
404         *
405         * @return      デバッグモードかどうか
406         */
407        protected final boolean isDebug() {
408                return debugFlag;
409        }
410
411        /**
412         * デバッグメッセージを追加します。
413         *
414         * @param       msg     追加するデバッグメッセージ
415         */
416        protected final void debug( final String msg ) {
417                debugMsg.append( msg ).append( CR );
418        }
419
420        /**
421         * 指定されたキーを大文字に変化後、値を返します。
422         *
423         * @og.rev 8.3.0.1 (2022/08/12) 新規作成
424         *
425         * @param       key     キー
426         *
427         * @return      変数値
428         */
429        private final String mapGet( final String key ) {
430                if( key == null ) { return null; }
431                else {
432                        return variableMap.get( key.toUpperCase(Locale.JAPAN) );
433                }
434        }
435
436        /**
437         * 指定されたキーの値を返します。
438         *
439         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
440         *
441         * @param       key     キー
442         *
443         * @return      変数値
444         */
445        protected final String var( final String key ) {
446//              return variableMap.get( key );
447                return mapGet( key );
448        }
449
450        /**
451         * 指定されたキーの値を返します。
452         *
453         * 値が、nullや空文字列の場合は、def引数の初期値を返します。
454         *
455         * @og.rev 8.0.2.0 (2021/11/30) 新規追加
456         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
457         *
458         * @param       key     キー
459         * @param       def     値が取得できなかった時の初期値
460         *
461         * @return      変数値
462         */
463        protected final String var( final String key,final String def ) {
464                // Map#getOrDefault( key,def ) ではなく、nval を使います。
465//              return StringUtil.nval( variableMap.get( key ) , def );
466                return StringUtil.nval( mapGet( key ) , def );
467        }
468
469        /**
470         * 指定されたキーの値をint型に変換して返します。
471         *
472         * 値が、nullや空文字列の場合は、def引数の初期値を返します。
473         *
474         * @og.rev 8.0.2.0 (2021/11/30) 新規追加
475         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
476         *
477         * @param       key     キー
478         * @param       def     値が取得できなかった時の初期値
479         *
480         * @return      変数値
481         */
482        protected final int var( final String key,final int def ) {
483                // Map#getOrDefault( key,def ) ではなく、nval を使います。
484//              return StringUtil.nval( variableMap.get( key ) , def );
485                return StringUtil.nval( mapGet( key ) , def );
486        }
487
488        /**
489         * 指定されたキーの値をdouble型に変換して返します。
490         *
491         * 値が、nullや空文字列の場合は、def引数の初期値を返します。
492         *
493         * @og.rev 8.0.2.0 (2021/11/30) 新規追加
494         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
495         *
496         * @param       key     キー
497         * @param       def     値が取得できなかった時の初期値
498         *
499         * @return      変数値
500         */
501        protected final double var( final String key,final double def ) {
502                // Map#getOrDefault( key,def ) ではなく、nval を使います。
503//              return StringUtil.nval( variableMap.get( key ) , def );
504                return StringUtil.nval( mapGet( key ) , def );
505        }
506
507//      /**
508//       * 指定されたキーの値をint型に変換して返します。
509//       *
510//       * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。
511//       * @og.rev 8.0.2.0 (2021/11/30) 廃止 vari(String) → var(String,int)
512//       *
513//       * @param       key     キー
514//       *
515//       * @return      変数値
516//       */
517//      protected final int vari( final String key ) {
518//              return str2int( var( key ) );                   // 6.7.9.1 (2017/05/19)
519//      }
520
521//      /**
522//       * 指定されたキーの値をdouble型に変換して返します。
523//       *
524//       * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。
525//       * @og.rev 8.0.2.0 (2021/11/30) 廃止 vari(String) → var(String,double)
526//       *
527//       * @param       key     キー
528//       *
529//       * @return      変数値
530//       */
531//      protected final double vard( final String key ) {
532//              return str2dbl( var( key ) );                   // 6.7.9.1 (2017/05/19)
533//      }
534
535        /**
536         * パラメーターのキー一覧を配列形式で返します。
537         * このパラメーターは、業務ロジック内でセットされたパラメーターも含まれますのでご注意下さい。
538         *
539         * @return      パラメーターのキー配列
540         */
541        protected final String[] varKeys() {
542                final Set<String> keys = variableMap.keySet();
543                return keys.toArray( new String[keys.size()] );
544        }
545
546        /**
547         * 指定されたキーで値を登録します。
548         * パラメーターとしてこの業務ロジックが呼ばれる際の引数となっている場合は、
549         * エラーとなります。
550         *
551         * @og.rev 5.2.1.0 (2010/10/01) チェックのバグを修正
552         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
553         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
554         *
555         * @param       key     キー
556         * @param       val     値
557         */
558        protected final void set( final String key, final String val ) {
559                // 6.0.2.5 (2014/10/31) 素直に、variableMap で、キー有無を判定する。
560//              if( variableMap.containsKey( key ) ) {
561                if( mapGet( key ) != null ) {
562                        final String errMsg = "すでに登録済みのキーを定義することはできません。"        + CR
563                                                        + "   key =" + key                              + CR
564                                                        + "   val =" + val                              + CR
565//                                                      + "   元  =" + variableMap.get( key ) ;
566                                                        + "   元  =" + mapGet( key ) ;
567                        throw new OgRuntimeException( errMsg );
568                }
569
570//              variableMap.put( key, val );
571                if( key != null ) {
572                        variableMap.put( key.toUpperCase(Locale.JAPAN), val );
573                }
574        }
575
576        /**
577         * 指定されたキーで値(int型)を登録します。
578         * パラメーターとしてこの業務ロジックが呼ばれる際の引数となっている場合は、
579         * エラーとなります。
580         *
581         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
582         *
583         * @param       key     キー
584         * @param       val     値
585         */
586        protected final void set( final String key, final int val ) {
587                set( key, String.valueOf( val ) );
588        }
589
590        /**
591         * 指定されたキーで値(double型)を登録します。
592         * パラメーターとしてこの業務ロジックが呼ばれる際の引数となっている場合は、
593         * エラーとなります。
594         *
595         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
596         *
597         * @param       key     キー
598         * @param       val     値
599         */
600        protected final void set( final String key, final double val ) {
601                set( key, String.valueOf( val ) );
602        }
603
604//      /**
605//       * 処理中の行の指定されたキー(カラム名)の値を返します。
606//       *
607//       * @og.rev 8.0.2.0 (2021/11/30) lineメソッド廃止(いまいち、使い道がない)
608//       *
609//       * @param       key     キー
610//       *
611//       * @return      値
612//       */
613//      protected final String line( final String key ) {
614//              return line( key, row );
615//      }
616
617//      /**
618//       * メインの配列型テーブルモデルに対して、行を指定して値を取得します。
619//       * 指定された行が範囲を超えている場合は、nullを返します。
620//       *
621//       * @og.rev 5.1.8.0 (2010/07/01) テーブルに存在しないカラム名を指定した場合に、NullPointerExceptionが発生するバグを修正
622//       * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
623//       * @og.rev 8.0.2.0 (2021/11/30) lineメソッド廃止(いまいち、使い道がない)
624//       *
625//       * @param       key     キー
626//       * @param       rw      行番号(インデックス)
627//       *
628//       * @return      値
629//       */
630//      protected final String line( final String key, final int rw ) {
631//              if( table == null ) {
632//                      // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
633//                      final String errMsg = "配列型テーブルモデルがセットされていないため、#line( String,int )メソッドはできません。"        + CR
634//                                                      + "   line( " + key + "," + rw + " );"  + CR ;
635//                      throw new OgRuntimeException( errMsg );
636//              }
637//              // 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
638//
639//              final int col = table.getColumnNo( key );
640//
641//              return col < 0 || rw < 0 || rw >= table.getRowCount() ? null : table.getValue( rw, col );
642//      }
643
644//      /**
645//       * 処理中の行の指定されたカラム番号の値を返します。
646//       * line( String )は、毎回、カラム番号を取得しているため、非効率です。
647//       * ただし、一旦カラム名から、カラム番号を取得し、それを使用するのと、
648//       * linei(String)や、lined(String) などの直接的なメソッドもないため、
649//       * 利用者側でそのあたりの処理を入れる必要があります。
650//       *
651//       * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。
652//       * @og.rev 8.0.2.0 (2021/11/30) lineメソッド廃止(いまいち、使い道がない)
653//       *
654//       * @param       col     カラム番号
655//       * @return      値
656//       */
657//      protected final String line( final int col ) {
658//              return line( col, row );
659//      }
660
661//      /**
662//       * メインの配列型テーブルモデルに対して、行を指定して値を取得します。
663//       * 指定された行が範囲を超えている場合は、nullを返します。
664//       *
665//       * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。
666//       * @og.rev 8.0.2.0 (2021/11/30) lineメソッド廃止(いまいち、使い道がない)
667//       *
668//       * @param       col     カラム番号
669//       * @param       rw      行番号(インデックス)
670//       * @return      値
671//       */
672//      protected final String line( final int col, final int rw ) {
673//              if( table == null ) {
674//                      // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
675//                      final String errMsg = "配列型テーブルモデルがセットされていないため、#line( String,int )メソッドはできません。"        + CR
676//                                                      + "   line( " + col + "," + rw + " );"  + CR ;
677//                      throw new OgRuntimeException( errMsg );
678//              }
679//
680//              return col < 0 || rw < 0 || rw >= table.getRowCount() ? null : table.getValue( rw, col );
681//      }
682
683//      /**
684//       * 処理中の行の指定されたキー(カラム名)の値をint型に変換して返します。
685//       *
686//       * @og.rev 6.7.9.0 (2017/04/28) row を使用して、#linei( String,int )を呼びます。
687//       * @og.rev 8.0.2.0 (2021/11/30) lineメソッド廃止(いまいち、使い道がない)
688//       *
689//       * @param       key     キー
690//       *
691//       * @return      値
692//       */
693//      protected final int linei( final String key ) {
694//              return str2int( line( key, row ) );                     // 6.7.9.1 (2017/05/19)
695//      }
696
697//      /**
698//       * メインの配列型テーブルモデルに対して、行を指定して値をint型に変換して返します。
699//       * 指定された行が範囲を超えている場合は、nullを返します。
700//       *
701//       * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。
702//       * @og.rev 8.0.2.0 (2021/11/30) lineメソッド廃止(いまいち、使い道がない)
703//       *
704//       * @param       key     キー
705//       * @param       rw      行番号(インデックス)
706//       *
707//       * @return      値
708//       */
709//      protected final int linei( final String key, final int rw ) {
710//              return str2int( line( key, rw ) );                      // 6.7.9.1 (2017/05/19)
711//      }
712
713//      /**
714//       * 処理中の行の指定されたキー(カラム名)の値をdouble型に変換して返します。
715//       *
716//       * @og.rev 6.7.9.0 (2017/04/28) row を使用して、#lined( String,int )を呼びます。
717//       * @og.rev 8.0.2.0 (2021/11/30) lineメソッド廃止(いまいち、使い道がない)
718//       *
719//       * @param       key     キー
720//       *
721//       * @return      値
722//       */
723//      protected final double lined( final String key ) {
724//              return str2dbl( line( key, row ) );                     // 6.7.9.1 (2017/05/19)
725//      }
726
727//      /**
728//       * メインの配列型テーブルモデルに対して、行を指定して値をdouble型に変換して返します。
729//       * 指定された行が範囲を超えている場合は、nullを返します。
730//       *
731//       * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。
732//       * @og.rev 8.0.2.0 (2021/11/30) lineメソッド廃止(いまいち、使い道がない)
733//       *
734//       * @param       key     キー
735//       * @param       rw      行番号(インデックス)
736//       *
737//       * @return      値
738//       */
739//      protected final double lined( final String key, final int rw ) {
740//              return str2dbl( line( key, rw ) );                      // 6.7.9.1 (2017/05/19)
741//      }
742
743        /**
744         * 指定のカラム名引数に相当するデータを2重配列で返します。
745         *
746         * @og.rev 6.8.5.0 (2018/01/09) 新規追加
747         *
748         * @param       clmNms  値が参照されるカラム名配列(可変長引数)
749         *
750         * @return      指定された名引数に相当するデータの2重配列
751         * @og.rtnNotNull
752         */
753        protected String[][] getValues( final String... clmNms ) {
754                // 6.9.8.0 (2018/05/28) FindBugs:コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している
755                if( table == null ) {
756                        final String errMsg = "配列型テーブルモデルがセットされていないため、#getValues( String... )メソッドはできません。"    + CR
757                                                        + "   clmNms= " + Arrays.toString( clmNms ) + " );"     + CR ;
758                        throw new OgRuntimeException( errMsg );
759                }
760
761                return ((ArrayTableModel)table).getValues( clmNms );
762        }
763
764//      /**
765//       * 文字列を整数に変換します。
766//       * 文字列が、nullか、空文字列の場合は、0 を返します。
767//       *
768//       * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。
769//       * @og.rev 8.0.2.0 (2021/11/30) str2intメソッド廃止(必要であれば、StringUtilを使用)
770//       *
771//       * @param       val     入力文字列
772//       * @return      int値
773//       */
774//      protected final int str2int( final String val ) {
775//              return val == null || val.isEmpty() ? 0 : Integer.parseInt( val );
776//      }
777
778//      /**
779//       * 文字列をdoubleに変換します。
780//       * 文字列が、nullか、空文字列の場合は、0d を返します。
781//       *
782//       * @og.rev 6.7.9.1 (2017/05/19) 文字列をdoubleに変換します。
783//       * @og.rev 8.0.2.0 (2021/11/30) str2dblメソッド廃止(必要であれば、StringUtilを使用)
784//       *
785//       * @param       val     入力文字列
786//       * @return      double値
787//       */
788//      protected final double str2dbl( final String val ) {
789//              return val == null || val.isEmpty() ? 0d : Double.parseDouble( val );
790//      }
791
792        /**
793         * 文字列配列をdouble配列に変換します。
794         * 文字列が、nullか、空文字列の場合は、長さ0の配列を返します。
795         *
796         * @og.rev 6.8.5.0 (2018/01/09) 新規追加
797         * @og.rev 8.0.2.0 (2021/11/30) StringUtil#nval(String.doubleを使用)
798         *
799         * @param       vals    double配列に変換する元の文字列配列
800         * @return      指定された文字列配列に対するdoubleに変換された値配列
801         * @og.rtnNotNull
802         */
803        protected final double[][] str2dblVals( final String[][] vals ) {
804                if( vals == null || vals.length == 0 || vals[0] == null || vals[0].length == 0 ) {
805                        return new double[0][0];
806                }
807
808                final int rowLen = vals.length;
809                final int colLen = vals[0].length;
810
811                final double[][] dbls = new double[rowLen][colLen];
812
813                for( int row=0; row<rowLen; row++ ) {
814                        for( int col=0; col<colLen; col++ ) {
815//                              dbls[row][col] = str2dbl( vals[row][col] );
816                                dbls[row][col] = StringUtil.nval( vals[row][col],0d );  // 8.0.2.0 (2021/11/30)
817                        }
818                }
819
820                return dbls;
821        }
822
823        /**
824         * テーブルのカラム名の一覧を配列形式で返します。
825         *
826         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
827         * @og.rev 8.0.2.0 (2021/11/30) メソッド名変更(lineKeys → getNames)
828         *
829         * @return      テーブルのカラム名配列
830         */
831//      protected final String[] lineKeys() {
832        protected final String[] getNames() {
833                if( table == null ) {
834                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
835                        final String errMsg = "配列型テーブルモデルがセットされていないため、#lineKeys()メソッドはできません。" ;
836                        throw new OgRuntimeException( errMsg );
837                }
838                else {
839                        return table.getNames();
840                }
841        }
842
843//      /**
844//       * テーブルにカラムが存在しているかを返します。
845//       *
846//       * @og.rev 5.2.0.0 (2010/09/01)
847//       * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
848//       * @og.rev 8.0.2.0 (2021/11/30) isLineメソッド廃止(必要なら、DataModel#getColumnNo(String) で判定する)
849//       *
850//       * @param       clm     カラム名
851//       *
852//       * @return      存在している場合true、存在していない場合false
853//       */
854//      protected final boolean isLine( final String clm ) {
855//              if( table == null ) {
856//                      // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
857//                      final String errMsg = "配列型テーブルモデルがセットされていないため、#isLine( String )メソッドはできません。"  + CR
858//                                                      + "   isLine( " + clm + " );"   + CR ;
859//                      throw new OgRuntimeException( errMsg );
860//              }
861//              return table.getColumnNo( clm ) >= 0 ;
862//      }
863
864        /**
865         * 業務ロジックの戻り値をセットします。
866         *
867         * @param       rtn     戻り値
868         */
869        protected final void rtn( final String rtn ) {
870                bizRtn = rtn;
871        }
872
873//      /**
874//       * 子ロジックを実行します。
875//       * 実行する子ロジックの呼び出しは、親クラスと同じソースパス、クラスパスで呼び出しされます。
876//       * 子ロジックに渡す引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
877//       * また、子ロジックの戻り値は、val("SUB_RETURN")で取得することができます。
878//       *
879//       * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すメソッドは廃止。
880//       *
881//       * @param       subLogicName    子ロジック名
882//       * @param       key                             キー(CSV形式)
883//       * @param       val                             値(CSV形式)
884//       *
885//       * @return      処理が正常終了したか
886//       */
887//      protected final boolean call( final String subLogicName, final String key, final String val ) {
888//              return call( subLogicName, key, val, row, table );
889//      }
890
891        /**
892         * 子ロジックを実行します。
893         * 実行する子ロジックの呼び出しは、親クラスと同じソースパス、クラスパスで呼び出しされます。
894         * 子ロジックに渡す引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
895         * この場合の値は、引数で指定された、配列型テーブルモデルの行に対応する値になります。
896         * また、子ロジックの戻り値は、val("RETURN")で取得することができます。
897         *
898         * @og.rev 5.1.9.0 (2010/08/01) シーケンス対応
899         * @og.rev 5.4.1.0 (2011/11/01) 値にカンマが含まれている場合に正しく動作しないバグを修正
900         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
901         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
902         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
903         * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すメソッドは廃止。
904         *
905         * @param       subLogicName    子ロジック名
906         * @param       key                             キー(CSV形式)
907         * @param       val                             値(CSV形式)
908//       * @param       rw                              行番号(インデックス)
909//       * @param       tbl                             配列型テーブルモデル
910         *
911         * @return      処理が正常終了したか
912         */
913//      protected final boolean call( final String subLogicName, final String key, final String val, final int rw, final DataModel<String> tbl ) {
914        protected final boolean call( final String subLogicName, final String key, final String val ) {
915                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
916                if( loader == null ) {
917                        final String errMsg = "#setLoader(HybsLoader)を先に実行しておいてください。"   + CR
918                                                        + "   subLogicName =" + subLogicName    + CR
919                                                        + "   key =" + key      + CR
920                                                        + "   val =" + val      + CR
921                                                        + "   ArrayTableModel=" + table ;
922                        throw new OgRuntimeException( errMsg );
923                }
924
925                final AbstractBizLogic subLogic = (AbstractBizLogic)loader.newInstance( subLogicName );
926
927                if( subLogic.isRequireTable() ) {
928                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
929                        final String errMsg = "このクラスは、外部からテーブルモデルをセットする必要があるため、子ロジックとして呼び出すことはできません。" + CR
930                                                        + "  [クラス名=" + subLogic.getClass().getName() + "]"      + CR
931                                                        + "   subLogicName =" + subLogicName
932                                                        + "   key =[" + key + "]"
933                                                        + "   val =[" + val + "]" + CR ;
934                        throw new OgRuntimeException( errMsg );
935                }
936
937                subLogic.setTransaction( tran );
938                subLogic.setLoader( loader );
939                subLogic.setKeys( StringUtil.csv2Array( key ) );
940                // 5.4.1.0 (2011/11/01) 値にカンマが含まれている場合に正しく動作しないバグを修正
941                // 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
942                final String[] vals = StringUtil.csv2Array( val );
943                replaceParam( vals );                   // 8.0.2.0 (2021/11/30) 配列内部を書き換えます。
944//              for( int i=0; i<vals.length; i++ ) {
945//                      vals[i] = replaceParam( vals[i], row, table );
946//              }
947                subLogic.setVals( vals );
948                subLogic.setUserId( variableMap.get( "CON.USERID" ) );
949                subLogic.setParentPgId( variableMap.get( "CON.PGID" ) );
950                if( debugFlag ) {
951                        subLogic.setDebug();
952                }
953
954                final boolean rtn;                                              // 6.3.9.0 (2015/11/06) Found 'DU'-anomaly for variable(PMD)
955                try {
956                        rtn = subLogic.exec();
957                }
958                catch( final Throwable th ) {
959                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
960                        final String errMsg = "子ロジックの呼び出しでエラーが発生しました。" + CR
961                                                        + "   subLogicName =" + subLogicName  + CR
962                                                        + "   key =[" + key + "]"
963                                                        + "   val =[" + val + "]" + CR ;
964                        throw new OgRuntimeException( errMsg ,th );
965                }
966                variableMap.put( "RETURN", subLogic.getReturn() );
967
968                if( debugFlag ) { debug( subLogic.getDebugMsg() ); }
969
970                final ErrMsg[] errs = subLogic.getErrMsg().toArray();
971                if( errs.length > 0 ) {
972                        final ErrorMessage errMsgTmp = new ErrorMessage();
973                        for( int i=0; i<errs.length; i++ ) {
974                                errMsgTmp.addMessage( errs[i].copy( row ) );
975                        }
976                        errMsg.append( errMsgTmp );
977                }
978
979                return rtn;
980        }
981
982//      /**
983//       * SQLを実行します。
984//       * SQL文には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
985//       * select文を発行した場合、その結果セットは、var(カラム名)で取得することができます。
986//       * 2行以上が返された場合でも、1行目のみが登録されます。
987//       * また、検索件数、更新件数については、var("SQL_ROWCOUNT")で取得することができます。
988//       *
989//       * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すメソッドは廃止。
990//       *
991//       * @param       sq      SQL文字列
992//       */
993//      protected final void sql( final String sq ) {
994//              sql( sq, row, table );
995//      }
996
997        /**
998         * SQLを実行します。
999         * SQL文には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
1000         * [XXXX]形式の変数の置き換えには、引数で指定された配列型テーブルモデルの行が使用されます。
1001         * select文を発行した場合、その結果セットは、var(カラム名)で取得することができます。
1002         * 2行以上が返された場合でも、1行目のみが登録されます。
1003         * また、検索件数、更新件数については、var("SQL_ROWCOUNT")で取得することができます。
1004         *
1005         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
1006         * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すメソッドは廃止。
1007         *
1008         * @param       sq      SQL文字列
1009//       * @param       rw      行番号(インデックス)
1010//       * @param       tbl     配列型テーブルモデル
1011         */
1012//      protected final void sql( final String sq, final int rw, final DataModel<String> tbl ) {
1013        protected final void sql( final String sq ) {
1014                final DataModel<String> tbl2 = execSQL( sq, row, table );
1015
1016                if( tbl2 != null && tbl2.getRowCount() > 0 ) {
1017                        final String[] names = tbl2.getNames();
1018                        final String[] vals = tbl2.getValues( 0 );
1019                        for( int i=0; i<names.length; i++ ) {
1020                                variableMap.put( names[i], vals[i] );                                                   // execSQLでnamesを大文字化済
1021                        }
1022                }
1023        }
1024
1025        /**
1026         * シーケンス名よりシーケンスオブジェクトを検索し、次の値を取り出します。
1027         * DBに対するシーケンスオブジェクトは予め作成されている必要があります。
1028         *
1029         * また、MySQLの場合は、シーケンスオブジェクトが実装されていないため、
1030         * 内部的には、引数のシーケンス名と同じ名前のテーブルから、Integer型の
1031         * "SEQID"という項目名を検索することにより、シーケンスをエミュレートしています。
1032         *
1033         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
1034         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
1035         *
1036         * @param       seqName シーケンス名
1037         *
1038         * @return      シーケンス番号
1039         * @see org.opengion.fukurou.db.DBFunctionName#getSequence(String,Transaction)
1040         */
1041        protected final int seq( final String seqName ) {
1042                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
1043                if( dbName == null ) {
1044                        final String errMsg = "#exec()を先に実行しておいてください。"  + CR
1045                                                        + "   seqName =" + seqName ;
1046                        throw new OgRuntimeException( errMsg );
1047                }
1048
1049                return dbName.getSequence( seqName, tran );
1050        }
1051
1052        /**
1053         * SQLを実行します。
1054         *
1055         * @param       sq      SQL文字列
1056         * @param       rw      行番号(インデックス)
1057         * @param       tbl     配列型テーブルモデル
1058         *
1059         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
1060         *
1061         * @return      結果セット(配列型テーブルモデル)
1062         *
1063         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
1064         * @og.rev 5.1.8.0 (2010/07/01) column名は大文字化し、項目名の取得は#getColumnLabel()で行う。(PotgreSQL対応&バグ修正)
1065         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応
1066         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
1067         * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。
1068         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
1069         * @og.rev 6.9.3.0 (2018/03/26) ミス修正(検索件数のところを、フェッチ件数を取得していた)
1070         * @og.rev 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズを設定。
1071         */
1072        private DataModel<String> execSQL( final String sq, final int rw, final DataModel<String> tbl ) {
1073                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
1074                if( conn == null ) {
1075                        final String errMsg = "#setTransaction(Transaction)を先に実行しておいてください。"     + CR
1076                                                        + "   sql =" + sq               + CR
1077                                                        + "   ArrayTableModel=" + tbl ;
1078                        throw new OgRuntimeException( errMsg );
1079                }
1080
1081                String sql = replaceParam( sq, false ); // [XXXX]の変換はここでは行わない。
1082                Formatter format = null ;
1083                if( tbl != null && sql.indexOf( '[' ) >= 0 ) {
1084                        format = getFormatter( sql, tbl );
1085                        sql = format.getQueryFormatString();
1086                }
1087
1088                DataModel<String>       tbl2    = null;
1089                // 6.4.2.1 (2016/02/05) try-with-resources 文
1090                try( PreparedStatement pstmt = conn.prepareStatement( sql ) ) {
1091                        if( tbl != null && format != null ) {
1092                                final int[] clmNo = format.getClmNos();
1093
1094                                // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
1095                                if( useParamMetaData ) {
1096                                        final ParameterMetaData pMeta = pstmt.getParameterMetaData();
1097                                        for( int i=0; i<clmNo.length; i++ ) {
1098                                                final int type = pMeta.getParameterType( i+1 );
1099                                                // 5.3.8.0 (2011/08/01) setNull 対応
1100                                                final String val = tbl.getValue( rw, clmNo[i] );
1101                                                if( val == null || val.isEmpty() ) {
1102                                                        pstmt.setNull( i+1, type );
1103                                                }
1104                                                else {
1105                                                        pstmt.setObject( i+1, val, type );
1106                                                }
1107                                        }
1108                                }
1109                                else {
1110                                        for( int i=0; i<clmNo.length; i++ ) {
1111                                                pstmt.setObject( i+1, tbl.getValue( rw, clmNo[i] ) );
1112                                        }
1113                                }
1114                        }
1115                        final boolean status = pstmt.execute();
1116                        // 6.4.2.1 (2016/02/05) try-with-resources 文
1117                        try( ResultSet result = pstmt.getResultSet() ) {
1118                                if( status ) {
1119                                        result.setFetchSize( DB_FETCH_SIZE );                           // 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ
1120
1121                                        final ResultSetMetaData metaData = result.getMetaData();
1122                                        final int cols = metaData.getColumnCount();
1123
1124                                        String[] names = new String[cols];
1125                                        for( int i=0; i<cols; i++ ) {
1126                                                // 5.1.8.0 (2010/07/01) column名は大文字化し、項目名の取得は#getColumnLabel()で行う。(PotgreSQL対応&バグ修正)
1127                                                names[i] = metaData.getColumnLabel( i+1 ).toUpperCase( Locale.JAPAN );
1128                                        }
1129
1130                                        final String[][] tblVals = DBUtil.resultToArray( result, false );
1131                                        tbl2 = new ArrayTableModel( names, tblVals );
1132
1133//                                      variableMap.put( "SQL_ROWCOUNT", String.valueOf( pstmt.getFetchSize() ) );
1134                                        variableMap.put( "SQL_ROWCOUNT", String.valueOf( tbl2.getRowCount() ) );                        // 6.9.3.0 (2018/03/26) ミス修正
1135                                }
1136                                else {
1137                                        variableMap.put( "SQL_ROWCOUNT", String.valueOf( pstmt.getUpdateCount() ) );
1138                                }
1139                        }
1140                }
1141                catch( final SQLException ex ) {                // catch は、close() されてから呼ばれます。
1142                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
1143                        final String errMsg = "配列型テーブルモデルの生成に失敗しました。" + CR
1144                                                        + "   sql =" + sql              + CR
1145                                                        + "   ArrayTableModel=" + tbl ;
1146                        throw new OgRuntimeException( errMsg,ex );
1147                }
1148                return tbl2;
1149        }
1150
1151        /**
1152         * 検索用SQLを実行して、Consumer#accept に検索結果の配列を繰り返しセットします。
1153         *
1154         * 内部でResultSetValue のカーソルを回すため、大量のデータについて
1155         * 順次処理する場合に使用します。
1156         *
1157         * @og.rev 8.2.0.3 (2022/06/30) 内部でカーソルを回す検索用SQLを実行する
1158         * @og.rev 8.2.1.0 (2022/07/15) querySQL では、[XXXX]の変換 自体を行わない
1159         *
1160         * @param       sq              SQL文字列
1161         * @param       call    CallBack関数(Consumer)
1162         */
1163        protected void querySQL( final String sq , final Consumer<String[]> call ) {
1164                if( conn == null ) {
1165                        final String errMsg = "#setTransaction(Transaction)を先に実行しておいてください。"     + CR
1166                                                        + "   sql =" + sq               + CR ;
1167                        throw new OgRuntimeException( errMsg );
1168                }
1169
1170                final String sql = replaceParam( sq, false ); // [XXXX]の変換はここでは行わない。
1171//              8.2.1.0 (2022/07/15) querySQL では、[XXXX]の変換 自体を行わない
1172//              Formatter format = null ;
1173//              if( table != null && sql.indexOf( '[' ) >= 0 ) {
1174//                      format = getFormatter( sql, table );
1175//                      sql = format.getQueryFormatString();
1176//              }
1177
1178                try( PreparedStatement pstmt = conn.prepareStatement( sql ) ) {
1179                        try( ResultSet result = pstmt.executeQuery() ) {
1180        //                      result.setFetchSize( DB_FETCH_SIZE );
1181                                try( ResultSetValue rsv = new ResultSetValue( result ) ) {
1182                                        while( rsv.next() ) {
1183                                                call.accept( rsv.getValues() );
1184                                        }
1185                                }
1186                        }
1187                }
1188                catch( final SQLException ex ) {                // catch は、close() されてから呼ばれます。
1189                        final String errMsg = "検索系SQL の実行に生成に失敗しました。"   + CR
1190                                                        + "   sql =" + sql              + CR ;
1191                        throw new OgRuntimeException( errMsg,ex );
1192                }
1193        }
1194
1195        /**
1196         * エラーメッセージを追加します。
1197         * エラーメッセージの引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
1198         *
1199         * @param       kekka   エラーレベル
1200         * @param       id              エラーメッセージID
1201         * @param       args    エラーメッセージパラメーター
1202         */
1203        protected final void error( final int kekka, final String id, final String... args ) {
1204                error( row, kekka, id, args );
1205        }
1206
1207        /**
1208         * 行指定でエラーメッセージを追加します。
1209         * エラーメッセージの引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
1210         *
1211         * @param       rw              行番号(インデックス)
1212         * @param       kekka   エラーレベル
1213         * @param       id              エラーメッセージID
1214         * @param       args    エラーメッセージパラメーター
1215         */
1216        protected final void error( final int rw, final int kekka, final String id, final String... args ) {
1217                errMsg.addMessage( rw, kekka, id, replaceParam( args ) );
1218        }
1219
1220        /**
1221         * パラメーターの必須チェックを行います。
1222         * キーは、CSV形式で複数指定することができます。
1223         *
1224         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
1225         *
1226         * @param       cs      カラム(CSV形式)
1227         *
1228         * @return      エラーが発生した場合はfalse、それ以外はtrue
1229         */
1230        protected final boolean must( final String cs ) {
1231                if( cs == null || cs.isEmpty() ) {
1232                        return true;
1233                }
1234
1235                final String[] clms = StringUtil.csv2Array( cs );
1236                for( int i=0; i<clms.length; i++ ) {
1237//                      final String val = variableMap.get( clms[i] );                                          // 8.3.0.1 (2022/08/12)
1238                        final String val = mapGet( clms[i] );
1239                        if( val == null || val.isEmpty() ) {
1240//                              error( 2, "ERR0012", "{#" + clms[i] + "}" );
1241                                error( NG, "ERR0012", "{#" + clms[i] + "}" );                                   // 7.2.9.5 (2020/11/28)
1242                                return false ;
1243                        }
1244                }
1245                return true;
1246        }
1247
1248        /**
1249         * マスタチェックを行います。
1250         *
1251         * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加
1252         *
1253         * @see #exist(String, String, String, String, String, String)
1254         * @param       type    エラーチェックのタイプ
1255         * @param       tblId   テーブル名
1256         * @param       ns              カラム(CSV形式)
1257         * @param       vs              値(CSV形式)
1258         *
1259         * @return      エラーが発生した場合はfalse、それ以外はtrue
1260         */
1261        protected final boolean exist( final String type, final String tblId, final String ns, final String vs ) {
1262                return exist( type, tblId, ns, vs, null, null,true );
1263        }
1264
1265        /**
1266         * マスタチェックを行います。
1267         *
1268         * 引数に指定されたテーブル名、及び条件句を生成するためのカラム、値から
1269         * 件数を取得し、typeに応じて件数チェックを行います。
1270         * (カラム、値には、CSV形式で複数指定することができます)
1271         *  type=true  存在する場合true  存在しない場合false
1272         *  type=false 存在する場合false 存在しない場合true
1273         *  type=one   1件以内    true  2件以上     false
1274         *
1275         * 必須チェックの引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
1276         *
1277         * また、固定値カラム、値にも条件となるカラム及び値を指定することができますが、
1278         * ここで指定されたカラムは、エラーメッセージ表示時にカラム、値が画面に表示されません。
1279         *
1280         * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加
1281         *
1282         * @param       type    エラーチェックのタイプ
1283         * @param       tblId   テーブル名
1284         * @param       ns              カラム(CSV形式)
1285         * @param       vs              値(CSV形式)
1286         * @param       conNs   固定値カラム(CSV形式)
1287         * @param       conVs   固定値(CSV形式)
1288         *
1289         * @return      エラーが発生した場合はfalse、それ以外はtrue
1290         */
1291        protected final boolean exist( final String type, final String tblId
1292                        , final String ns, final String vs, final String conNs, final String conVs ) {
1293                return exist( type, tblId, ns, vs, conNs, conVs,true );
1294        }
1295
1296        /**
1297         * マスタチェックを行います。
1298         * 引数に指定されたテーブル名、及び条件句を生成するためのカラム、値から
1299         * 件数を取得し、typeに応じて件数チェックを行います。
1300         * (カラム、値には、CSV形式で複数指定することができます)
1301         *  type=true  存在する場合true  存在しない場合false
1302         *  type=false 存在する場合false 存在しない場合true
1303         *  type=one   1件以内    true  2件以上     false
1304         *
1305         * 必須チェックの引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
1306         *
1307         * また、固定値カラム、値にも条件となるカラム及び値を指定することができますが、
1308         * ここで指定されたカラムは、エラーメッセージ表示時にカラム、値が画面に表示されません。
1309         *
1310         * isErrThrow は、エラーが発生した場合に、エラーメッセージ(ErrorMessage)に書き込むかどうかを指定します。
1311         * 基本は、互換性を考慮し、true(書き込む)です。
1312         * false にするケースは、存在チェックを行い、あれば更新、なければ追加 など後続処理を行いたい場合に使います。
1313         *
1314         * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加
1315         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
1316         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
1317         *
1318         * @param       type            エラーチェックのタイプ
1319         * @param       tblId           テーブル名
1320         * @param       ns                      カラム(CSV形式)
1321         * @param       vs                      値(CSV形式)
1322         * @param       conNs           固定値カラム(CSV形式)
1323         * @param       conVs           固定値(CSV形式)
1324         * @param       isErrThrow      判定結果がfalseの場合に、error関数を呼ぶ場合は、true。呼ばない場合は、falseをセットします。
1325         *
1326         * @return      エラーが発生した場合はfalse、それ以外はtrue
1327         */
1328        protected final boolean exist( final String type, final String tblId
1329                        , final String ns, final String vs, final String conNs, final String conVs, final boolean isErrThrow ) {
1330                if( ns == null || ns.isEmpty() || vs == null || vs.isEmpty() ) {
1331                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
1332                        final String errMsg = "カラム又は、値にnullは指定できません。"   + CR
1333                                                        + "   ns =[" + ns + "]"
1334                                                        + "   vs =[" + vs + "]" ;
1335                        throw new OgRuntimeException( errMsg );
1336                }
1337
1338                final String namesStr   = ns + ( conNs == null || conNs.isEmpty() ? "" : "," + conNs );
1339                final String[] namesArr = StringUtil.csv2Array( namesStr );
1340                final String valsStr    = vs + ( conVs == null || conVs.isEmpty() ? "" : "," + conVs );
1341                final String[] valsArr  = StringUtil.csv2Array( valsStr );
1342                if( namesArr.length != valsArr.length ) {
1343                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
1344                        final String errMsg = "カラムと値の個数が異なります。"                 + CR
1345                                                        + "   names = [" + namesStr     + "]"   + CR
1346                                                        + "   vals  = [" + valsStr      + "]";
1347                        throw new OgRuntimeException( errMsg );
1348                }
1349
1350                final StringBuilder sb = new StringBuilder( BUFFER_MIDDLE );
1351                sb.append( "select count(*) CNT from " ).append( tblId );
1352                for( int i=0 ;i<namesArr.length; i++ ) {
1353                        if( i==0 )      { sb.append( " where " ); }
1354                        else            { sb.append( " and " ); }
1355                        sb.append( namesArr[i] ).append( " = " ).append( valsArr[i] );
1356                }
1357
1358                int count = 0;
1359                final DataModel<String> tbl2 = execSQL( sb.toString(), row, table );            // 6.7.9.1 (2017/05/19)
1360                if( tbl2 != null && tbl2.getRowCount() >= 0 ) {
1361                        count = Integer.parseInt( tbl2.getValues( 0 )[0] );                     // 6.0.2.4 (2014/10/17) メソッド間違い
1362                }
1363
1364                final String repVals = replaceParam( vs );
1365                if( "true".equalsIgnoreCase( type ) ) {
1366                        // ERR0025=データ未登録エラー。キー={0}、値={1} のデータは、存在していません。
1367                        if( count <= 0 ) {
1368                                if( isErrThrow ) { error( NG, "ERR0025", "{#" + ns + "}", repVals ); }  // 5.6.3.1 (2013/04/05)
1369                                return false;
1370                        }
1371                }
1372                else if( "false".equalsIgnoreCase( type ) ) {
1373                        // ERR0026=データ登録済みエラー。キー={0}、値={1} のデータは、すでに存在しています。
1374                        if( count > 0 ) {
1375                                if( isErrThrow ) { error( NG, "ERR0026", "{#" + ns + "}", repVals ); }  // 5.6.3.1 (2013/04/05)
1376                                return false;
1377                        }
1378                }
1379                else if( "one".equalsIgnoreCase( type ) ) {
1380                        // ERR0027=データ2重登録エラー。キー={0}、値={1} のデータは、重複して存在しています。
1381                        if( count > 1 ) {
1382                                if( isErrThrow ) { error( NG, "ERR0027", "{#" + ns + "}", repVals ); }  // 5.6.3.1 (2013/04/05)
1383                                return false;
1384                        }
1385                }
1386                else {
1387                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
1388                        final String errMsg = "typeは、true、false、oneのいずれかで指定する必要があります。"  + CR
1389                                                        + "   type = [" + type  + "]";
1390                        throw new OgRuntimeException( errMsg );
1391                }
1392                return true;
1393        }
1394
1395        /**
1396         * 引数に指定されたキー、値をマップ形式に変換します。
1397         *
1398         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
1399         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
1400         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
1401         */
1402        private void makeParamMap() {
1403                if( keys != null && vals != null ) {
1404                        if( keys.length == vals.length ) {
1405                                for( int i=0; i<keys.length; i++ ) {
1406//                                      variableMap.put( keys[i], vals[i] );
1407                                        if( keys[i] != null ) {
1408                                                variableMap.put( keys[i].toUpperCase(Locale.JAPAN), vals[i] );  // 8.3.0.1 (2022/08/12)
1409                                        }
1410                                }
1411                        }
1412                        else {
1413                                // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。
1414                                final String errMsg = "keysとvalsの個数が異なります。"             + CR
1415                                                        + "   keys   =" + Arrays.toString( keys )               + CR
1416                                                        + "   vals   =" + Arrays.toString( vals ) ;
1417                                throw new OgRuntimeException( errMsg );
1418                        }
1419                }
1420
1421                final String ymdh = DateSet.getDate( "yyyyMMddHHmmss" );                // 5.5.7.2 (2012/10/09) HybsDateUtil を利用
1422                variableMap.put( "CON.YMDH", ymdh );
1423                variableMap.put( "CON.YMD", ymdh.substring( 0,8 ) );
1424                variableMap.put( "CON.HMS", ymdh.substring( 8 ) );
1425
1426                variableMap.put( "CON.PGID", this.getClass().getSimpleName() );
1427        }
1428
1429        /**
1430         * {&#064;XXXX}形式及び[XXXX]形式の文字列配列の置き換えを行います。
1431         *
1432         * @og.rev 6.2.2.0 (2015/03/27) #replaceParam( String[] , int , ArrayTableModel ) 廃止に伴う処置
1433         * @og.rev 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
1434         *
1435         * @param       str     置き換え対象の配列
1436         *
1437         * @return      置き換え結果の文字列(引数配列の内部を書き換えます)
1438         */
1439        private String[] replaceParam( final String[] str ) {
1440                for( int i=0; i<str.length; i++ ) {
1441//                      str[i] = replaceParam( str[i], row, table );
1442                        str[i] = replaceParam( str[i], true );                  // [XXXX]の変換を行う。
1443                }
1444                return str;
1445        }
1446
1447        /**
1448         * {&#064;XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。
1449         *
1450         * @og.rev 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
1451         *
1452         * @param       str     置き換え対象の文字列
1453         *
1454         * @return      置き換え結果の文字列
1455         */
1456        private String replaceParam( final String str ) {
1457//              return replaceParam( str, row, table );
1458                return replaceParam( str, true );                                       // [XXXX]の変換を行う。
1459        }
1460
1461//      /**
1462//       * {&#064;XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。
1463//       * isRepTableにfalseを指定した場合、Formatterによる[XXXX]変換は行われません。
1464//       * (SQLの変換の場合は、PreparedStatementで処理させるため、[XXXX]の変換は行わない。)
1465//       *
1466//       * @og.rev 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
1467//       *
1468//       * @param       str                     置き換え対象の文字列
1469//       * @param       isRepTable      Formatterによる[XXXX]変換を行うか
1470//       *
1471//       * @return      置き換え結果の文字列
1472//       */
1473//      private String replaceParam( final String str, final boolean isRepTable ) {
1474//              return isRepTable ? replaceParam( str, row, table) : replaceParam( str, 0, null ) ;
1475//      }
1476
1477        /**
1478         * {&#064;XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。
1479         * [XXXX]形式の置き換えには、引数で指定された配列型テーブルモデル、行番号(インデックス)を使用します。
1480         *
1481         * @og.rev 5.1.8.0 (2010/07/01) 引数チェック漏れ対応
1482         * @og.rev 5.3.9.0 (2011/09/01) nullが連続する場合にゼロストリングに置き換えられないバグを修正
1483         * @og.rev 6.4.3.2 (2016/02/19) Formatterを、値が null の場合は、ゼロ文字列を設定する。
1484         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
1485         * @og.rev 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
1486         *
1487         * @param       str                     置き換え対象の文字列
1488         * @param       isRepTable      Formatterによる[XXXX]変換を行うか
1489//       * @param       rw                      行番号(インデックス)
1490//       * @param       tbl                     配列型テーブルモデル
1491         *
1492         * @return      置き換え結果の文字列
1493         */
1494//      private String replaceParam( final String str, final int rw, final DataModel<String> tbl ) {
1495        private String replaceParam( final String str, final boolean isRepTable ) {
1496                // 5.1.8.0 (2010/07/01) 引数チェック漏れ対応
1497                if( str == null || str.isEmpty() ) { return ""; }
1498
1499                String rtn = str;
1500
1501                // {@XXXX}の変換
1502                if( !variableMap.isEmpty() && rtn.indexOf( "{@" ) >= 0 ) {              // 6.1.1.0 (2015/01/17) refactoring
1503                        final SystemParameter sysParam = getSysParam( rtn );
1504                        rtn = sysParam.replace( variableMap );
1505                }
1506
1507                // [XXXX]の変換
1508//              if( tbl != null && rtn.indexOf( '[' ) >= 0 ) {
1509                if( isRepTable && rtn.indexOf( '[' ) >= 0 ) {
1510                        final Formatter format = getFormatter( rtn, table );
1511                        rtn = format.getFormatString( row );
1512                }
1513
1514                return rtn;
1515        }
1516
1517        /**
1518         * [XXXX]変換を行うためのFormatterを取得します。
1519         *
1520         * @og.rev 6.4.3.4 (2016/03/11) Formatterに新しいコンストラクターを追加する。
1521         * @og.rev 6.4.3.4 (2016/03/11) Map#computeIfAbsent で対応する。
1522         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
1523         *
1524         * @param       str     変換文字列
1525         * @param       tbl     配列型テーブルモデル
1526         *
1527         * @return      Formatterオブジェクト
1528         */
1529        private Formatter getFormatter( final String str, final DataModel<String> tbl ) {
1530                // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
1531                final String key = str + tbl.toString();
1532                return formatMap.computeIfAbsent( key , k -> new Formatter( tbl,str ) );
1533        }
1534
1535        /**
1536         * {&#064;XXXX}変換を行うためのSystemParameterオブジェクトを取得します。
1537         *
1538         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加
1539         *
1540         * @param       str     変換文字列
1541         *
1542         * @return      SystemParameterオブジェクト
1543         */
1544        private SystemParameter getSysParam( final String str ) {
1545                // 6.4.3.3 (2016/03/04) キーが null のときも、SystemParameter オブジェクトを構築しているので、
1546                // それも合わせて、Mapで管理するようにします。
1547                final String key = str == null ? "NULL" : str ;
1548                // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
1549                return sysParamMap.computeIfAbsent( key , k -> new SystemParameter( k ) );
1550        }
1551
1552//      /**
1553//       * 検索SQLを実行し、結果を配列型テーブルモデルとして返します。
1554//       * SQL文には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
1555//       * また、検索件数については、var("SQL_ROWCOUNT")で取得することができます。
1556//       *
1557//       * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
1558//       * @og.rev 8.0.2.0 (2021/11/30) BizLogic_CURSOR で使用しているだけなので、廃止。
1559//       *
1560//       * @param       sq      SQL文
1561//       *
1562//       * @return      配列型テーブルモデル
1563//       */
1564//      protected final DataModel<String> createTableBySql( final String sq ) {
1565////            return createTableBySql( sq, row, table );
1566//              return execSQL( sq, row, table );
1567//      }
1568
1569//      /**
1570//       * 検索SQLを実行し、結果を配列型テーブルモデルとして返します。
1571//       * SQL文には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
1572//       * [XXXX]形式の変数の置き換えには、引数で指定された配列型テーブルモデルの行が使用されます。
1573//       * また、検索件数については、var("SQL_ROWCOUNT")で取得することができます。
1574//       *
1575//       * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
1576//       * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すメソッドは廃止。
1577//       *
1578//       * @param       sq      SQL文
1579//       * @param       rw      行番号(インデックス)
1580//       * @param       tbl     配列型テーブルモデル
1581//       *
1582//       * @return      配列型テーブルモデル
1583//       */
1584//      protected final DataModel<String> createTableBySql( final String sq, final int rw, final DataModel<String> tbl ) {
1585//              return execSQL( sq, rw, tbl );
1586//      }
1587
1588        /**
1589         * 変数に関連付けた値を、返します。
1590         * これは、BizLogicから、呼び出し元のJSPに、RETURN 変数以外の {&#064;XXXX} パラメータを返します。
1591         * 既存のアトリビュートがあれば、上書きされます。
1592         *
1593         * @og.rev 6.9.9.0 (2018/08/20) 戻り値を返せるようにします。
1594         *
1595         * @param       key     キー
1596         * @param       val     値
1597         *
1598         */
1599        protected final void setRtnMap( final String key, final String val ) {
1600                if( key != null && val != null ) {                      // ConcurrentMap なので。
1601                        rtnMap.put( key, val );
1602                }
1603        }
1604
1605        /**
1606         * 変数に関連付けた値を、返します。
1607         * これは、BizLogicから、呼び出し元のJSPに、RETURN 変数以外の {&#064;XXXX} パラメータを返します。
1608         * 既存のアトリビュートがあれば、上書きされます。
1609         *
1610         * @og.rev 6.9.9.0 (2018/08/20) 戻り値を返せるようにします。
1611         *
1612         * @return      内部マップオブジェクト
1613         */
1614        protected final Map<String,String> getReturnMap() {
1615                return rtnMap;
1616        }
1617}