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 static org.opengion.fukurou.util.StringUtil.*;
019
020import java.io.IOException;
021import java.io.ObjectInputStream;
022import java.io.ObjectOutputStream;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.Locale;
026
027import org.opengion.fukurou.db.DBUtil;
028import org.opengion.fukurou.db.Transaction;
029import org.opengion.fukurou.db.TransactionReal;
030import org.opengion.fukurou.util.ErrorMessage;
031import org.opengion.fukurou.util.StringUtil;
032import org.opengion.hayabusa.common.HybsSystem;
033import org.opengion.hayabusa.common.HybsSystemException;
034import org.opengion.hayabusa.db.DBColumn;
035import org.opengion.hayabusa.db.DBEditConfig;
036import org.opengion.hayabusa.db.DBTableModel;
037import org.opengion.hayabusa.db.Query;
038import org.opengion.hayabusa.db.QueryFactory;
039import org.opengion.hayabusa.resource.GUIInfo;
040
041/**
042 * データベースの検索を行うタグです。
043 *
044 * このタグの内容に、SQL文を記述します。 whereタグ、 andタグ を使うと引数に応じて
045 * 実行されるSQL文が異なります(使用例参照)。
046 * また、PL/SQLのSPで検索を行うときもこのタグを使います。
047 * SystemData の USE_SQL_INJECTION_CHECK が true か、quotCheck 属性が true の場合は、
048 * SQLインジェクション対策用のクォーティションチェックを行います。リクエスト引数に
049 * クォーティション(')が含まれると、エラーになります。
050 * 同様にUSE_XSS_CHECKがtrueか、xssCheck属性がtrueの場合は、
051 * クロスサイトススクリプティング(XSS)対策のためless/greater than signのチェックを行います。
052 *
053 * ※ このタグは、Transaction タグの対象です。
054 *
055 * @og.formSample
056 * ●形式:
057 *       ・<og:query command="NEW" >
058 *              SELECT文 
059 *         </og:query>
060 *       ・<og:query command="NEW" names="・・・" queryType="JDBCErrMsg" >
061 *              { call PL/SQL(?,?,?,? ) } 
062 *         </og:query>
063 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
064 *
065 * ●Tag定義:
066 *   <og:query
067 *       queryType          【TAG】Query を発行する為のクラスID(JDBC,JDBCCallable,JDBCErrMsg,JDBCUpdate)を指定します{@og.doc03Link queryType 初期値:JDBC})
068 *       command            【TAG】コマンド(NEW,RENEW)をセットします(PlsqlUpdateTag,UpdateTag の場合は、ENTRY)
069 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
070 *       maxRowCount        【TAG】(通常は使いません)データの最大読み込み件数を指定します (初期値:DB_MAX_ROW_COUNT[=1000])(0:[無制限])
071 *       skipRowCount       【TAG】(通常は使いません)データの読み始めの初期値を指定します
072 *       displayMsg         【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します (初期値:VIEW_DISPLAY_MSG[=])
073 *       overflowMsg        【TAG】検索データが最大検索数をオーバーした場合に表示するメッセージリソースIDを指定します (初期値:MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました])
074 *       notfoundMsg        【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])
075 *       names              【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します
076 *       stopZero           【TAG】検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])
077 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
078 *       dbid               【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します
079 *       trace              【TAG】引数の SQL 文を EXPLAIN PLAN を[true:行う/それ以外:行わない]を指定します(初期値:false)
080 *       checkNames         【TAG】リクエスト変数の正規化を行うカラムをCSV形式で複数指定します
081 *       modifyType         【TAG】DB検索時の モディファイタイプを指定します[A:追加/C:更新/D:削除]
082 *       quotCheck          【TAG】リクエスト情報の クォーティション(') 存在チェックを実施するかどうか[true/false]を設定します(初期値:USE_SQL_INJECTION_CHECK)
083 *       stopError          【TAG】PLSQL/SQL処理エラーの時に処理を中止するかどうか[true/false]を設定します(初期値:true)
084 *       dispError                      【TAG】エラー時にメッセージを表示するか[true/false]を設定します。通常はstopErrorと併用(初期値:true)
085 *       xssCheck           【TAG】リクエスト情報の HTMLTag開始/終了文字(><) 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_XSS_CHECK[=true])
086 *       mainTrans          【TAG】(通常使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:true)
087 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
088 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
089 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:true)
090 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:true)
091 *       useBeforeHtmlTag   【TAG】 処理時間(queryTime)などの情報出力[true:有効/false:無効]を指定します(初期値:true)
092 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
093 *   >   ... Body ...
094 *   </og:query>
095 *
096 * ●使用例
097 *     <og:query command="NEW">
098 *             select PN,YOBI,NMEN,HINM from XX01 where PN = '{@PN}' order by PN
099 *     </og:query>
100 *
101 *          ・検索条件が入力された時({@PN}がNOT NULLのとき)
102 *            作成されるSQL文⇒select PN,YOBI,NMEN,HINM from XX01 where PN = 'AAA' order by PN
103 *          ・検索条件が入力されなかった時({@PN}がNULLのとき)
104 *            作成されるSQL文⇒select PN,YOBI,NMEN,HINM from XX01 where PN = '' order by PN
105 *
106 *     <og:query command="NEW">
107 *             select PN,YOBI,NMEN,HINM from XX01
108 *         <og:where>
109 *             <og:and value="PN = '{@PN}%'" />
110 *             <og:and value="YOBI like '{@YOBI}%'" />
111 *         </og:where>
112 *             order by PN
113 *     </og:query>
114 *
115 *          ・検索条件が入力された時({@PN}がNOT NULLのとき)
116 *            作成されるSQL文⇒select PN,YOBI,NMEN,HINM from XX01 PN = 'AAA%' and YOBI like 'BBB%' order by PN
117 *          ・検索条件が入力されなかった時({@PN}がNULLのとき) WHERE句がなくなる。
118 *            作成されるSQL文⇒select PN,YOBI,NMEN,HINM from XX01 order by PN
119 *
120 *        注意:WhereTagを使った場合、下のようにはなりません。
121 *            select PN,YOBI,NMEN,HINM from XX01 PN = '' and YOBI like '%' order by PN
122 *
123 *     <og:query command="NEW">
124 *             select PN,YOBI,NMEN,HINM from XX01 where PN="11111"
125 *         <og:where startKey="and">
126 *             <og:and value="YOBI like '{@PN}%'" />
127 *         </og:where>
128 *             order by PN
129 *     </og:query>
130 *
131 *          ・検索条件が入力された時({@YOBI}がNOT NULLのとき)
132 *            作成されるSQL文⇒select PN,YOBI,NMEN,HINM from XX01 PN = '11111' and YOBI like 'BBB%' order by PN
133 *          ・検索条件が入力されなかった時({@YOBI}がNULLのとき) WHERE句がなくなる。
134 *            作成されるSQL文⇒select PN,YOBI,NMEN,HINM from XX01 PN = '11111' order by PN
135 *
136 *     <og:query
137 *          command    = "NEW"
138 *          names      = "SYSTEM_ID,LANG,CLM,NAME_JA,LABEL_NAME,KBSAKU,USER.ID"
139 *          checkNames = "CLM,NAME_JA"
140 *          queryType  = "JDBCErrMsg"
141 *          displayMsg = "">
142 *              {call TYPE3B01.TYPE3B01(?,?,?,?)}
143 *     </og:query>
144 *
145 *          ・queryType に JDBCErrMsg を指定して、PL/SQL をコールできます。
146 *            引数は、names 属性をキーにリクエスト変数から読み込みます。
147 *          ・checkNames にカラム名を指定すると、columns.valueSet による
148 *            リクエスト変数の正規化を行います。
149 *
150 * @og.group DB検索
151 * @og.group DB登録
152 *
153 * @version  4.0
154 * @author       Kazuhiko Hasegawa
155 * @since    JDK5.0,
156 */
157public class QueryTag extends CommonTagSupport {
158        //* このプログラムのVERSION文字列を設定します。   {@value} */
159        private static final String VERSION = "5.6.5.3 (2013/06/28)" ;
160
161        private static final long serialVersionUID = 565320130628L ;
162
163        /** command 引数に渡す事の出来る コマンド  新規 {@value} */
164        public static final String CMD_NEW       = "NEW" ;
165        /** command 引数に渡す事の出来る コマンド  再検索 {@value} */
166        public static final String CMD_RENEW = "RENEW" ;
167        /** command 引数に渡す事の出来る コマンド リスト  */
168        private static final String[] COMMAND_LIST = new String[] { CMD_NEW , CMD_RENEW };
169
170        /** エラーメッセージID {@value} */
171        protected static final String errMsgId   = HybsSystem.ERR_MSG_KEY;
172
173        private   String        queryType       = null;
174        // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
175//      private   String        dbid            = "DEFAULT";
176        private   String        dbid            = null ;
177        protected transient DBTableModel        table           = null;
178        protected transient ErrorMessage        errMessage      = null;
179        protected String        tableId         = HybsSystem.TBL_MDL_KEY;
180        protected String        command         = CMD_NEW;
181        protected int           skipRowCount = 0;
182        protected int           maxRowCount     = -1;
183        protected String        sql                     = null;
184        protected int           executeCount = -1;                      // 検索/実行件数
185        protected String        names           = null;
186        protected boolean       outMessage      = true;
187        protected int           errCode         = ErrorMessage.OK;
188        protected boolean       quotCheck       = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );      // 4.0.0 (2005/08/31)
189        private   boolean       trace           = false;                // 4.0.0 (2005/01/31) 廃止
190        private   boolean       stopZero        = false;
191        private   String        modifyType      = null;                 // 3.8.5.1 (2006/05/08) modifyType 属性を追加します。
192//      private   String        displayMsg      = "MSG0033";    //  件検索しました。
193        protected String        displayMsg      = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
194        private   String        overflowMsg     = "MSG0007";    // 検索結果が、制限行数を超えましたので、残りはカットされました。
195        private   String        notfoundMsg     = "MSG0077";    // 対象データはありませんでした。
196        private   boolean       isMainTrans     = true;                 // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
197
198        // 3.5.4.7 (2004/02/06) 実行時間測定用のDIV要素を出力します。
199        protected long dyStart = 0;
200        // 4.3.3.0 (2008/09/22) PLSQL/SQL実行エラーの際に、処理を中止するかどうか。
201        protected boolean stopError             = true;
202        
203        // 5.9.26.1 (2017/11/10) 実行エラーの際に、エラーを画面に出力するかどうか。
204        protected boolean dispError             = true;
205
206        private StringBuilder debugMsg = null;          // 3.5.6.0 (2004/06/18)
207
208        // 3.8.0.5 (2005/08/20) リクエスト変数の正規化を行います。
209        private String                  checkNames      = null;
210
211        // 3.8.5.3 (2006/08/07) トレース時のメッセージ文字列を保存しておきます。
212        private String                  traceMsg        = null;
213
214        protected boolean       xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" );        // 5.0.0.2 (2009/09/15)
215
216        // 5.3.5.0 (2011/05/01) 処理時間(queryTime)などの情報出力の有効/無効を指定します。
217        private boolean         useBeforeHtmlTag        = true ;
218
219        // 5.10.2.1 (2018/08/18) where-andタグのplaceHolder情報を保持する
220        private transient List<String> listPlaceValue = null;
221        
222        /**
223         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
224         *
225         * @og.rev 3.5.4.7 (2004/02/06) 実行時間測定用に、開始時刻を取得します。
226         * @og.rev 3.5.6.5 (2004/08/09) 暫定的に、DBTableModelを先行削除します。
227         * @og.rev 3.6.0.0 (2004/09/24) DBTableModel の先行削除は、scope="session" の場合のみ。
228         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
229         * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
230         * @og.rev 5.10.23.0 (2020/06/01) SKIPBODY時もstopZeroを動作させる7.2.5.0対応を入れておく
231         *
232         * @return      後続処理の指示
233         */
234        @Override
235        public int doStartTag() {
236                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
237                if( useTag() ) {
238                        dyStart = System.currentTimeMillis();
239//                      if( ! check( command, COMMAND_LIST ) ) { return(SKIP_BODY); }
240                    if( ! check( command, COMMAND_LIST ) ) { // 5.10.23.0 
241                        table = (DBTableModel)getObject( tableId );
242                        if( table != null ) { executeCount = table.getRowCount(); }
243
244                        return SKIP_BODY ;
245                    }
246
247                        useMainTrans( isMainTrans );                    // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
248                        startQueryTransaction( tableId );               // 3.6.0.8 (2004/11/19)
249
250                        // 3.5.6.5 (2004/08/09) 削除するのは、セッションのオブジェクトでよい。
251                        // 3.6.0.0 (2004/09/24) 削除するのは、scope="session" の場合のみ。
252                        if( "session".equals( getScope() ) ) {
253                                removeSessionAttribute( tableId );
254                                removeSessionAttribute( HybsSystem.VIEWFORM_KEY );
255                        }
256
257                        return( EVAL_BODY_BUFFERED );   // Body を評価する。( extends BodyTagSupport 時)
258                }
259                return ( SKIP_BODY );                           // Body を評価しない
260        }
261
262        /**
263         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
264         *
265         * @og.rev 3.1.1.0 (2003/03/28) ボディの内容を取得する処理を、CommonTagSupport で行う。
266         * @og.rev 3.6.0.8 (2004/11/19) エラー発生時に確実にリリースされるように try finally 追加
267         * @og.rev 3.8.5.3 (2006/08/07) USER.LASTSQL へのSQL文の保存は、実行前に行っておきます。
268         * @og.rev 3.8.6.3 (2006/11/30) SQL 文の前後のスペースを取り除きます。
269         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
270         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
271         * @og.rev 4.0.0.0 (2005/08/31) useQuotCheck() によるSQLインジェクション対策
272         * @og.rev 4.3.4.0 (2008/12/01) GE20(ユーザー定数)へ登録するかのフラグへの対応
273         * @og.rev 5.0.0.2 (2009/09/15) XSS対応
274         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
275         * @og.rev 5.1.9.0 (2010/08/01) TransactionTag 対応。上位に TransactionTag があれば、そこからConnection をもらう。
276         * @og.rev 5.3.6.0 (2011/06/01) 集計、合計などのEdit機能に対応します。
277         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
278         * @og.rev 5.3.7.0 (2011/07/01) PL/SQLかつscope="request"で正しく出力するためqueryType,namesも保存する。
279         * @og.rev 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
280         * @og.rev 5.5.3.4 (2012/06/19) trace 時は、実際の検索処理を行わない様に変更。
281         * @og.rev 5.6.5.3 (2013/06/28) LASTQUERYTYPE ⇒ LASTSQLTYPE 変更。
282         *
283         * @return      後続処理の指示(SKIP_BODY)
284         */
285        @Override
286        public int doAfterBody() {
287
288                // 4.0.0 (2005/08/31) useQuotCheck() によるSQLインジェクション対策
289                useQuotCheck( quotCheck );
290                // 5.0.0.2 (2009/09/15) XSS対策
291                useXssCheck( xssCheck );
292
293                sql = getBodyString().trim();
294
295                // 3.2.1.0 (2003/05/28) 最終SQL文を、UserInfo に、キャッシュしておく。
296//              setUserInfo( "LASTSQL", sql );
297                // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
298                if( isMainTrans ) {
299                        setUserInfo( "LASTSQL", sql, false );
300                        // 5.3.7.0 (2011/07/01) PL/SQLかつscope="request"で正しく出力するためqueryType,namesも保存する。
301//                      setUserInfo( "LASTQUERYTYPE", queryType, false );
302                        setUserInfo( "LASTSQLTYPE", queryType, false );                         // 5.6.5.3 (2013/06/28)
303                        setUserInfo( "LASTNAMES", names, false );
304                }
305
306                Query query = QueryFactory.newInstance( queryType );
307                Transaction tran = null;
308                try {
309                        if( maxRowCount < 0 ) {
310                                maxRowCount     = sysInt( "DB_MAX_ROW_COUNT" );
311                        }
312
313                        // 5.1.9.0 (2010/08/01) TransactionTag 対応
314//                      final Transaction tran ;
315                        TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class );
316                        if( tranTag == null ) {
317//                              tran = new TransactionReal( dbid,getApplicationInfo() );
318                                tran = new TransactionReal( getApplicationInfo() );             // 5.3.7.0 (2011/07/01) 引数変更
319                        }
320                        else {
321                                tran = tranTag.getTransaction();
322                        }
323                        query.setTransaction( dbid,tran );      // 5.1.9.0 (2010/08/01) TransactionTag 対応
324
325                        query.setSkipRowCount( skipRowCount );
326                        query.setMaxRowCount( maxRowCount );
327//                      query.setConnectionID( dbid );
328                        query.setResourceManager( getResource() );      // 4.0.0 (2005/01/31)
329
330                        if( trace ) {
331//                              traceMsg = traceQuery( sql );
332                                traceMsg = traceQuery( sql,tran );              // 5.1.9.0 (2010/08/01) TransactionTag 対応
333                                // 5.5.3.4 (2012/06/19) trace 時は、実際の検索処理を行わない様に変更
334//                              query.setMaxRowCount( 1 );
335                                return(SKIP_BODY);
336                        }
337                        query.setStatement( sql );
338//                      query.setApplicationInfo( getApplicationInfo() );       // 3.8.7.0 (2006/12/15)
339
340                        // 5.3.6.0 (2011/06/01) 集計、合計などのEdit機能に対応します。
341                        if( isMainTrans ) {
342                                String guikey = getGUIInfoAttri( "KEY" );
343                                String editName = getRequestValue( "editName" );
344                                DBEditConfig config = getUser().getEditConfig( guikey, editName );
345                                if( config != null ) {
346                                        query.setEditConfig( config );
347                                }
348                        }
349
350                        execute( query );
351
352                        executeCount = query.getExecuteCount();
353                        if( errCode < ErrorMessage.NG && executeCount >= 0 ) {            // 異常以外の場合
354                                table = query.getDBTableModel();
355                                // 3.8.5.1 (2006/05/08) modifyType 属性を追加します。
356                                if( modifyType != null ) {
357                                        for( int row=0; row<executeCount; row++ ) {
358                                                table.setModifyType( row,modifyType );
359                                        }
360                                }
361                        }
362                }
363                finally {
364//                      if( query != null ) { query.close(); }
365                        QueryFactory.close( query );
366                        if( tran != null ) { tran.close(); }            // 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
367                }
368                return(SKIP_BODY);
369        }
370
371        /**
372         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
373         *
374         * @og.rev 2.0.0.8 (2002/10/09) command="NEW" のときのみ、displayMsg を表示させます。
375         * @og.rev 2.1.1.4 (2002/11/25) デバッグ時に最終SQLをユーザー情報をセットするように変更。
376         * @og.rev 2.1.2.1 (2002/11/27) ErrorMessage をクリアしないように変更。
377         * @og.rev 3.1.1.0 (2003/03/28) JspWriter オブジェクトの使用箇所を、jspPrint() を使用するように変更。
378         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
379         * @og.rev 3.2.1.0 (2003/05/28) 最終SQL文を、UserInfo に、キャッシュしておく。
380         * @og.rev 3.3.3.3 (2003/08/06) 検索結果の件数を、"DB.COUNT" キーでリクエストにセットする。
381         * @og.rev 3.3.3.3 (2003/08/06) 検索結果を、"DB.ERR_CODE" キーでリクエストにセットする。
382         * @og.rev 3.5.4.7 (2004/02/06) 実行時間測定用のDIV要素を出力しておきます。
383         * @og.rev 3.5.4.9 (2004/02/25) 警告時に停止していましたが、継続処理させます。
384         * @og.rev 3.5.5.0 (2004/03/12) ErrorMessage オブジェクトを、query が成功した時にもクリアするように変更
385         * @og.rev 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用
386         * @og.rev 3.5.5.8 (2004/05/20) ErrorMessage オブジェクトを、コマンドが NEW の場合のみ、クリア
387         * @og.rev 3.5.6.0 (2004/06/18) debugMsg 属性を出力するように修正します。
388         * @og.rev 3.6.0.8 (2004/11/19) DBTableModel をセーブする時に、トランザクションチェックを行います。
389         * @og.rev 3.8.5.3 (2006/08/07) USER.LASTSQL へのSQL文の保存は、実行前に行っておきます。
390         * @og.rev 4.0.0.0 (2006/11/14) notfoundMsg 属性を追加。displayMsg は、VIEW_USE_DISPLAY_MSG で制御
391         * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
392         * @og.rev 4.3.3.0 (2008/09/22) 属性 stopError の設定により、JSP処理を中止するかどうかを制御します。
393         * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
394         * @og.rev 5.3.5.0 (2011/05/01) 処理時間(queryTime)などの情報出力の有効/無効を指定します。
395         * @og.rev 5.5.0.3 (2012/03/13) オーバーフローメッセージが存在しないときは、何もしない。(改行も入れない)
396         * @og.rev 5.5.3.4 (2012/06/19) trace 時は、実際の検索処理を行わない様に変更。
397         * @og.rev 5.6.3.0 (2013/04/01) エラー時メッセージ変更
398         * @og.rev 5.9.16.1 (2017/11/10) dispErrorの動作追加
399         * @og.rev 5.10.2.2 (2018/08/24) 一部のエラーをjspPrintから標準のErrorMessageに変更
400         *
401         * @return      後続処理の指示
402         */
403        @Override
404        public int doEndTag() {
405                debugPrint();           // 4.0.0 (2005/02/28)
406                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
407                if( !useTag() ) { return(EVAL_PAGE); }
408
409                if( trace ) {
410                        jspPrint( traceMsg );
411                        return (SKIP_PAGE);             // 5.5.3.4 (2012/06/19) trace 時は、実際の検索処理を行わない様に変更。
412                }
413
414                String label  = "";                             // 4.0.0 (2005/11/30) 検索しなかった場合。
415                if( check( command, COMMAND_LIST ) ) {
416                        StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_SMALL );
417
418                        // 実行件数の表示 command="NEW" のときのみ、displayMsg を表示させます。
419                        // 4.0.0 (2005/11/30) 出力順の変更。一番最初に出力します。
420//                      boolean useStatusBar = HybsSystem.sysBool( "VIEW_USE_DISPLAY_MSG" );
421                        if( CMD_NEW.equals( command ) ) {
422//                              if( useStatusBar && executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
423                                if( executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
424                                        buf.append( executeCount );
425//                                      buf.append( getResource().getMessage( displayMsg ) );
426                                        buf.append( getResource().getLabel( displayMsg ) );
427                                        buf.append( HybsSystem.BR );
428                                }
429                                else if( executeCount == 0 && notfoundMsg != null && notfoundMsg.length() > 0 ) {
430//                                      buf.append( getResource().getMessage( notfoundMsg ) );
431                                        buf.append( getResource().getLabel( notfoundMsg ) );
432                                        buf.append( HybsSystem.BR );
433                                }
434                        }
435
436                        // 3.3.3.3 (2003/08/06) 検索結果の件数を、"DB.COUNT" キーでリクエストにセットする。
437                        setRequestAttribute( "DB.COUNT"   , String.valueOf( executeCount ) );
438                        // 3.3.3.3 (2003/08/06) 検索結果を、"DB.ERR_CODE" キーでリクエストにセットする。
439                        setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
440
441                        // オーバーフロー時のメッセージを表示
442//                      if( table != null && table.isOverflow() ) {
443                        // 5.5.0.3 (2012/03/09) オーバーフローメッセージが存在しないときは、何もしない。(改行も入れない)
444                        if( table != null && table.isOverflow() && overflowMsg != null && overflowMsg.length() > 0  ) {
445//                              buf.append( getResource().getMessage( overflowMsg ) );
446                                buf.append( getResource().getLabel( overflowMsg ) );
447                                buf.append( HybsSystem.BR );
448                        }
449                        
450                        // 5.10.2.2 (2018/08/24) 6.9.9.0  「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
451                        if( table != null && ! commitTableObject( tableId, table ) ) {
452                                if( errMessage == null ) { errMessage = new ErrorMessage( "QueryTag Query Error!" ); }
453                                // ERR0041:検索処理中に割り込みの検索要求がありました。処理されません。
454                                errMessage.addMessage( 0,ErrorMessage.NG,"ERR0041" );   
455                                errCode = ErrorMessage.NG;
456                        }
457
458                        // 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用
459                        String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
460                        if( err != null && err.length() > 0 ) {
461                                buf.append( err );
462                                setSessionAttribute( errMsgId,errMessage );
463                        }
464                        else if( CMD_NEW.equals( command ) ) {          // 3.5.5.8 (2004/05/20)
465                                removeSessionAttribute( errMsgId );
466                        }
467                        label = buf.toString();
468                        
469                        // 5.9.26.1 (2017/11/10) エラーメッセージをリクエスト変数で持つようにしておく
470                        setRequestAttribute( "DB.ERR_MSG", label );
471//                      //  5.10.2.2 (2018/08/24) 6.9.9.0
472//                      if( table != null && ! commitTableObject( tableId, table ) ) {
473//                              // 3.6.0.8 (2004/11/19) トランザクションチェックを行います。
474//                              // jspPrint( "QueryTag Query処理が割り込まれました。DBTableModel は登録しません。" );
475//                              
476//                              // 5.6.4.0 (2013/04/01) リソースから出力するように対応
477//                              ErrorMessage errMsgObj = new ErrorMessage( "QueryTag Query Error!" );
478//                              errMsgObj.addMessage( 0,ErrorMessage.NG,"ERR0041" );
479//                              jspPrint( TaglibUtil.makeHTMLErrorTable( errMsgObj,getResource() ) );
480//                              
481//                              return (SKIP_PAGE);
482//                      }
483                }
484                
485                // 5.9.26.1 (2017/11/10) dispErrorで表示をコントロール
486                if( dispError ) {
487                        jspPrint( label );
488                }
489
490                // 3.5.4.9 (2004/02/25) 警告時に停止していましたが、継続処理させます。
491//              int rtnCode = EVAL_PAGE;
492                final int rtnCode ;
493                if( errCode >= ErrorMessage.NG )  {  // 異常
494                        if( stopError ) {                               // 4.3.3.0 (2008/09/22) 属性 stopError の設定により、処理を中止するかを判断します。
495                                rtnCode = SKIP_PAGE;
496                        }
497                        else {
498                                rtnCode = EVAL_PAGE;
499                        }
500                }
501                else {
502                        // 件数0件かつ stopZero = true
503                        if( executeCount == 0 && stopZero )     {
504                                rtnCode = SKIP_PAGE;
505                        }
506                        else {
507                                rtnCode = EVAL_PAGE;
508                        }
509                }
510
511                // 3.5.4.7 (2004/02/06)
512                long dyTime = System.currentTimeMillis()-dyStart;
513
514                // 5.3.5.0 (2011/05/01) 処理時間(queryTime)などの情報出力の有効/無効を指定します。
515                if( useBeforeHtmlTag ) {
516                        jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );      // 3.5.6.3 (2004/07/12)
517                }
518
519                // 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録)
520                GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY );
521                if( guiInfo != null ) { guiInfo.addReadCount( executeCount,dyTime,sql ); }
522
523                return( rtnCode );
524        }
525
526        /**
527         * タグリブオブジェクトをリリースします。
528         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
529         *
530         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
531         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
532         * @og.rev 3.5.4.7 (2004/02/06) 実行時間測定用に、dyStart を追加します。
533         * @og.rev 3.5.6.0 (2004/06/18) debugMsg 属性を追加します。
534         * @og.rev 3.8.0.5 (2005/08/20) checkNames 属性を追加します。
535         * @og.rev 3.8.5.1 (2006/05/08) modifyType 属性を追加します。
536         * @og.rev 3.8.5.1 (2006/05/08) traceMsg 属性(トレース時のメッセージ文字列)を追加します。
537         * @og.rev 4.0.0.0 (2005/08/31) quotCheck 属性の追加
538         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
539         * @og.rev 4.3.3.0 (2008/09/22) stopError 属性の追加
540         * @og.rev 5.0.0.2 (2009/09/15) XSS対応
541         * @og.rev 5.1.6.0 (2010/05/01) DBLastSqlの処理は、DBTableModelが新規作成された処理でのみ行う。
542         * @og.rev 5.3.5.0 (2011/05/01) 処理時間(queryTime)などの情報出力の有効/無効を指定します。
543         * @og.rev 5.9.26.1 (2017/11/10) dispError追加
544         * @og.rev 5.10.2.1 (2018/08/18) プレースホルダ対応
545         *
546         */
547        @Override
548        protected void release2() {
549                super.release2();
550                tableId                 = HybsSystem.TBL_MDL_KEY;
551                queryType               = null;
552//              dbid                    = "DEFAULT";
553                dbid                    = null;
554                command                 = CMD_NEW;
555                skipRowCount    = 0;
556                maxRowCount             = -1;
557                table                   = null;
558                sql                             = null;
559//              displayMsg              = "MSG0033";    //  件検索しました。
560                displayMsg              = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
561                overflowMsg             = "MSG0007";    // 検索結果が、制限行数を超えましたので、残りはカットされました。
562                notfoundMsg             = "MSG0077";    // 対象データはありませんでした。
563                executeCount    = -1;                   // 検索/実行件数
564                names                   = null;
565                outMessage              = true;
566                trace                   = false;
567                errCode                 = ErrorMessage.OK;
568                errMessage              = null;
569                stopZero                = false;
570                stopError               = true;                 // 4.3.3.0 (2008/09/22)
571                dyStart                 = 0;
572                debugMsg                = null;                 // 3.5.6.0 (2004/06/18)
573                checkNames              = null;                 // 3.8.0.5 (2005/08/20)
574                quotCheck               = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );      // 4.0.0 (2005/08/31)
575                modifyType      = null;                 // 3.8.5.1 (2006/05/08)
576                traceMsg                = null;                 // 3.8.5.3 (2006/08/07)
577                xssCheck                = HybsSystem.sysBool( "USE_XSS_CHECK" );        // 5.0.0.2 (2009/09/15)
578                isMainTrans             = true;                 // 5.1.6.0 (2010/05/01) DBLastSqlの処理の見直し
579                useBeforeHtmlTag        = true ;        // 5.3.5.0 (2011/05/01)
580                dispError               = true;                 // 5.9.26.1 (2017/11/10)
581                listPlaceValue          = null;         // 5.10.2.1 (2018/08/18)
582        }
583
584        /**
585         * Query を実行します。
586         *
587         * @og.rev 2.1.2.3 (2002/12/02) データベース更新時に、更新フラグをセットするように変更
588         * @og.rev 3.4.0.0 (2003/09/01) 登録エラー時のキーと値を表示するように変更。
589         * @og.rev 3.5.6.0 (2004/06/18) デバッグ情報出力用に、printDebug メソッドを追加。
590         * @og.rev 3.6.1.0 (2005/01/05) エラーコードによる commit/rollback の判断追加
591         * @og.rev 5.3.7.0 (2011/07/01) nameの判定にゼロ文字列を付加
592         * @og.rev 5.10.2.1 (2018/08/18) プレースホルダ対応 
593         *
594         * @param       query オブジェクト
595         */
596        protected void execute( final Query query ) {
597                String[] nameArray = null;
598                String[] values    = null;
599                try {
600//                      if( names == null ) {
601                        if( names == null || names.length() == 0 ) {
602                                // 5.10.2.1 (2018/08/18) 
603                                // query.execute();
604                                if(listPlaceValue != null && !listPlaceValue.isEmpty()) {
605                                        // listPlaceValueに値が存在する場合は、listPlaceValueの値を渡す
606                                        values = listPlaceValue.toArray(new String[listPlaceValue.size()]);
607                                        query.execute(values);
608                                }else {
609                                        query.execute();
610                                }
611                        }
612                        else {
613                                nameArray = StringUtil.csv2Array( names );
614                                // 5.10.2.1 (2018/08/18) 
615//                              values = getRequest( nameArray );
616                                if(listPlaceValue != null && !listPlaceValue.isEmpty()) {
617                                        // listPlaceValueに値が存在する場合は、listPlaceValueの値を設定
618                                        values = listPlaceValue.toArray(new String[listPlaceValue.size()]);
619                                }else {
620                                        values = getRequest( nameArray );
621                                }
622                                
623                                // 3.5.6.0 (2004/06/18) デバッグ情報出力用
624                                if( isDebug() ) { printDebug( nameArray,values ); }
625                                
626                                query.execute( values );
627                        }
628                        errCode = query.getErrorCode();
629                        errMessage = query.getErrorMessage();
630                        // 3.6.1.0 (2005/01/05) エラーコードによる commit/rollback の判断追加
631//                      if( query.getUpdateFlag() ) {
632                        if( query.isUpdate() ) {
633                                if( errCode < ErrorMessage.NG ) {            // 異常以下の場合
634                                        query.commit();
635                                }
636                                else {
637                                        query.rollback();
638                                }
639                        }
640                }
641                catch( HybsSystemException ex ) {
642                        query.rollback();
643
644                        // 4.0.0 (2005/02/28) エラー時の表示とデバッグ時の表示を統一する。
645                        String errMsg = "DATABASE ERROR! " + HybsSystem.CR ;
646                        if( nameArray != null ) {
647                                printDebug( nameArray,values );
648                                errMsg += debugMsg;
649                        }
650                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
651                }
652                finally {
653                        if( query != null ) { query.close(); }
654                }
655        }
656
657        /**
658         * デバッグ用に、配列データを書き出します。
659         *
660         * @og.rev 3.5.6.0 (2004/06/18) 新規追加
661         *
662         * @param       nms     引数 names の配列データ
663         * @param       vals    names に対応するリクエスト情報の配列
664         */
665        private void printDebug( final String[] nms,final String[] vals ) {
666                if( debugMsg == null ) { debugMsg = new StringBuilder(); }
667
668                debugMsg.append( "  names=[" );
669                debugMsg.append( StringUtil.array2csv( nms ) );
670                debugMsg.append( "]" );
671                debugMsg.append( HybsSystem.CR );
672                debugMsg.append( "  values=[" );
673                debugMsg.append( StringUtil.array2csv( vals ) );
674                debugMsg.append( "]" );
675                debugMsg.append( HybsSystem.CR );
676        }
677
678        /**
679         * 名称配列を元に、リクエスト情報のデータを取得します。
680         * checkNames 属性に設定されているカラムがあれば、値を正規化します。
681         *
682         * @og.rev 3.8.0.5 (2005/08/20) リクエスト変数の正規化(checkNames)対応
683         *
684         * @param       nameArray       キーとなる名称の配列
685         *
686         * @return      そのリクエスト情報の配列
687         */
688        protected String[] getRequest( final String[] nameArray ) {
689                String[] rtn = new String[nameArray.length];
690
691                for( int i=0; i<rtn.length; i++ ) {
692                        rtn[i] = getRequestValue( nameArray[i] );
693
694                        // 3.8.0.5 (2005/08/20) checkNames があり、rtn[i] がある場合。
695                        if( checkNames != null && checkNames.length() > 0 && rtn[i].length() > 0 ) {
696                                if( ( "," + checkNames + "," ).indexOf( "," + nameArray[i] + "," ) >= 0 ) {
697                                        DBColumn dbColumn = getDBColumn( nameArray[i] );
698                                        String val = dbColumn.valueSet( rtn[i] );
699                                        if( val != null ) { rtn[i] = val; }
700                                }
701                        }
702                }
703
704                return rtn;
705        }
706        
707        /**
708         * 子タグ(andタグ)でプレースホルダーを設定した時に利用するメソッドです。
709         * queryタグ内部のプレースホルダリストに追加します。
710         *
711         * @og.rev 5.10.2.1 (2018/08/18) 新規追加
712         * @param trg 追加分
713         */
714        protected void addListPlaceValue(final String trg) {
715                if(listPlaceValue == null) {
716                        // listTestの初期化(初期化時にnamesの値を設定する)
717                        listPlaceValue = new ArrayList<String>();
718                        // namesをリストに追加
719                        String[] nameArray = StringUtil.csv2Array( names );
720                        String[] values = getRequest( nameArray );
721                        
722                        for(int i=0; i<values.length; i++) {
723                                listPlaceValue.add(values[i]);
724                        }
725                }
726                
727                // カンマで分割
728                String[] arrayTrg = StringUtil.csv2Array( trg );
729                for(int i=0; i<arrayTrg.length; i++) {
730                        // リクエストパラメータの値を変換して、リストに追加
731                        listPlaceValue.add(getRequestParameter(arrayTrg[i]));
732                }
733        }
734
735        /**
736         * 【TAG】(通常は使いません)データの読み始めの初期値を指定します。
737         *
738         * @og.tag
739         * データベース自体の検索は,指定されたSQLの全件を検索しますが,
740         * DBTableModelのデータとしては、スキップ件数分は登録されません。
741         * サーバーのメモリ資源と応答時間の確保の為です。
742         *
743         * @param       count 読み始めの初期値
744         */
745        public void setSkipRowCount( final String count ) {
746                skipRowCount = nval( getRequestParameter( count ),skipRowCount );
747        }
748
749        /**
750         * 【TAG】(通常は使いません)データの最大読み込み件数を指定します
751         *              (初期値:DB_MAX_ROW_COUNT[={@og.value org.opengion.hayabusa.common.SystemData#DB_MAX_ROW_COUNT}])。
752         *
753         * @og.tag
754         * データベース自体の検索は,指定されたSQLの全件を検索しますが,
755         * DBTableModelのデータとして登録する最大件数をこの値に設定します。
756         * サーバーのメモリ資源と応答時間の確保の為です。
757         * 0 をセットすると、無制限(Integer.MAX_VALUE)になります。
758         * (初期値:ユーザー定数のDB_MAX_ROW_COUNT[={@og.value org.opengion.hayabusa.common.SystemData#DB_MAX_ROW_COUNT}])。
759         *
760         * @og.rev 5.5.8.5 (2012/11/27) 0を無制限として処理します。
761         *
762         * @param       count 最大読み込み件数
763         * @see         org.opengion.hayabusa.common.SystemData#DB_MAX_ROW_COUNT
764         */
765        public void setMaxRowCount( final String count ) {
766                maxRowCount = nval( getRequestParameter( count ),maxRowCount );
767                if( maxRowCount == 0 ) { maxRowCount = Integer.MAX_VALUE ; }            // 5.5.8.5 (2012/11/27)
768        }
769
770        /**
771         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
772         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
773         *
774         * @og.tag
775         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
776         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
777         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
778         * この tableId 属性を利用して、メモリ空間を分けます。
779         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
780         *
781         * @param       id sessionに登録する時の ID
782         */
783        public void setTableId( final String id ) {
784                tableId   = nval( getRequestParameter( id ),tableId );  // 3.8.0.9 (2005/10/17)
785        }
786
787        /**
788         * 【TAG】Query を発行する為のクラスID(JDBC,JDBCCallable,JDBCErrMsg,JDBCUpdate)を指定します({@og.doc03Link queryType 初期値:JDBC})。
789         *
790         * @og.tag
791         * 検索を実行する手段は、Query インターフェースの実装クラスになります。
792         * このタグでは、Query.execute( String[] ) メソッドが呼ばれます。
793         * 例えば、ストアドプロシージャ等を実行する場合に、queryType="JDBCErrMsg"
794         * を指定することができます。
795         * 初期値は、"JDBC" です。
796         * queryType は、システムリソースの Query_**** 宣言の **** を与えます。
797         * これらは、Query インターフェースを継承したサブクラスである必要があります。
798         * 標準で、org.opengion.hayabusa.db 以下の Query_**** クラスが、Query_**** 宣言 と
799         * して、定義されています。
800         * 属性クラス定義の {@link org.opengion.hayabusa.db.Query Query} を参照願います。
801         * {@og.doc03Link queryType Query_**** クラス}
802         *
803         * @param       id Query を発行する為の実クラス ID
804         * @see         org.opengion.hayabusa.db.Query  Queryのサブクラス
805         * @see         org.opengion.hayabusa.db.Query#execute( String[] )
806         */
807        public void setQueryType( final String id ) {
808                queryType = getRequestParameter( id );
809        }
810
811        /**
812         * 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します。
813         *
814         * @og.tag
815         * Queryオブジェクトを作成する時のDB接続IDを指定します。
816         * これは、システムリソースで、DEFAULT_DB_URL 等で指定している データベース接続先
817         * 情報に、XX_DB_URL を定義することで、 dbid="XX" とすると、この 接続先を使用して
818         * データベースにアクセスできます。
819         *
820         * @param       id データベース接続ID
821         */
822        public void setDbid( final String id ) {
823                dbid = nval( getRequestParameter( id ),dbid );
824        }
825
826        /**
827         * 【TAG】コマンド(NEW,RENEW)をセットします(PlsqlUpdateTag,UpdateTag の場合は、ENTRY)。
828         *
829         * @og.tag
830         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
831         * フィールド定数値のいづれかを、指定できます。
832         *
833         * @param       cmd コマンド(public static final 宣言されている文字列)
834         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.QueryTag.CMD_NEW">コマンド定数</a>
835         */
836        public void setCommand( final String cmd ) {
837                String cmd2 = getRequestParameter( cmd );
838                if( cmd2 != null && cmd2.length() >= 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
839        }
840
841        /**
842         * 【TAG】検索結果が0件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])。
843         *
844         * @og.tag
845         * 初期値は、false(続行する)です。
846         *
847         * @param  cmd 検索結果が0件のとき、[true:処理を中止する/false:続行する]
848         */
849        public void setStopZero( final String cmd ) {
850                stopZero = nval( getRequestParameter( cmd ),stopZero );
851        }
852
853        /**
854         * 【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します
855         *              (初期値:VIEW_DISPLAY_MSG[={@og.value org.opengion.hayabusa.common.SystemData#VIEW_DISPLAY_MSG}])。
856         *
857         * @og.tag
858         * ここでは、検索結果の件数や登録された件数をまず出力し、
859         * その次に、ここで指定したメッセージをリソースから取得して表示します。
860         * 件数を表示させたい場合は、displayMsg = "MSG0033"[ 件検索しました] をセットしてください。
861         * 表示させたくない場合は, displayMsg = "" をセットしてください。
862         * (初期値:システム定数のVIEW_DISPLAY_MSG[={@og.value org.opengion.hayabusa.common.SystemData#VIEW_DISPLAY_MSG}])。
863         *
864         * @param       id ディスプレイに表示させるメッセージ ID
865         * @see         org.opengion.hayabusa.common.SystemData#VIEW_DISPLAY_MSG
866         */
867        public void setDisplayMsg( final String id ) {
868                String ids = getRequestParameter( id );
869                if( ids != null ) { displayMsg = ids; }
870        }
871
872        /**
873         * 【TAG】検索データが最大検索数をオーバーした場合に表示するメッセージリソースIDを指定します
874         *              (初期値:MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました])。
875         *
876         * @og.tag
877         * 検索結果が、maxRowCount で設定された値より多い場合、何らかのデータは検索されず
878         * 切り捨てられたことになります。
879         * ここでは、displayMsg を表示した後、必要に応じて、このメッセージを表示します。
880         * 表示させたくない場合は, overflowMsg = "" をセットしてください。
881         * 初期値は、MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました]です。
882         *
883         * @param       id ディスプレイに表示させるメッセージ ID
884         */
885        public void setOverflowMsg( final String id ) {
886                String ids = getRequestParameter( id );
887                if( ids != null ) { overflowMsg = ids; }
888        }
889
890        /**
891         * 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])。
892         *
893         * @og.tag
894         * ここでは、検索結果がゼロ件の場合のみ、特別なメッセージを表示させます。
895         * 従来は、displayMsg と兼用で、『0 件検索しました』という表示でしたが、
896         * displayMsg の初期表示は、OFF になりましたので、ゼロ件の場合のみ別に表示させます。
897         * 表示させたくない場合は, notfoundMsg = "" をセットしてください。
898         * 初期値は、MSG0077[対象データはありませんでした]です。
899         *
900         * @param       id ディスプレイに表示させるメッセージ ID
901         */
902        public void setNotfoundMsg( final String id ) {
903                String ids = getRequestParameter( id );
904                if( ids != null ) { notfoundMsg = ids; }
905        }
906
907        /**
908         * 【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します。
909         *
910         * @og.tag
911         * 複数ある場合は、カンマ区切り文字で渡します。
912         * names 属性は、queryType に応じて設定可否が異なりますので、ご注意ください。
913         * names なし:JDBC,JDBCUpdate
914         * names あり:JDBCCallable,JDBCErrMsg,JDBCUpdate
915         * (JDBCUpdateは、names 属性のあり/なし両方に対応しています。)
916         *
917         * @og.rev 3.0.1.3 (2003/03/11) names 属性に null で渡す場合のバグを修正
918         *
919         * @param       nm 引数の名称(複数ある場合は、カンマ区切り文字)
920         */
921        public void setNames( final String nm ) {
922                names = nval( getRequestParameter( nm ),names );
923        }
924
925        /**
926         * 【TAG】検索結果のメッセージを表示する/しない[true/false]を指定します(初期値:true)。
927         *
928         * @og.tag
929         * 初期値は、表示する:true です。
930         *
931         * @param       flag  [true:表示する/それ以外:含めない]
932         */
933        public void setOutMessage( final String flag ) {
934                outMessage = nval( getRequestParameter( flag ),outMessage );
935        }
936
937        /**
938         * 【TAG】引数の SQL 文を EXPLAIN PLAN を[true:行う/それ以外:行わない]を指定します(初期値:false)。
939         *
940         * @og.tag
941         *
942         * ここでは、以下の処理を行います。
943         * 1.引数の SQL 文を画面に表示します。
944         * 2.引数の SQL 文を EXPLAIN PLAN した結果を、画面に表示します。
945         * なお、以前は、セッションのトレースを行っていましたが、その機能は、廃止いたします。
946         * 初期値は、行わない:false です。
947         *
948         * @param       flag トレース [true:行う/それ以外:行わない]
949         */
950        public void setTrace( final String flag ) {
951                trace = nval( getRequestParameter( flag ),trace );
952        }
953
954        /**
955         * 【TAG】リクエスト変数の正規化を行うカラムをCSV形式で複数指定します。
956         *
957         * @og.tag
958         * PL/SQLを利用する場合の引数にセットすべき データを、リクエスト変数の
959         * 値そのままではなく、カラムオブジェクトの valueSet メソッド経由で正規化
960         * した値を使用するようにします。
961         *
962         * @og.rev 3.8.0.5 (2005/08/20) 新規追加
963         *
964         * @param       nm リクエスト変数の正規化を行うカラム
965         */
966        public void setCheckNames( final String nm ) {
967                checkNames = nval( getRequestParameter( nm ),checkNames );
968        }
969
970        /**
971         * 【TAG】DB検索時の モディファイタイプを指定します[A:追加/C:更新/D:削除]。
972         *
973         * @og.tag
974         * DB検索時に、そのデータをA(追加)、C(更新)、D(削除)のモディファイタイプを
975         * つけた状態にします。
976         * その状態で、そのまま、update する事が可能になります。
977         *
978         * @og.rev 3.8.5.1 (2006/05/08) 新規追加
979         *
980         * @param   type DB検索時の モディファイタイプ [A:追加/C:更新/D:削除]
981         */
982        public void setModifyType( final String type ) {
983                modifyType = nval( getRequestParameter( type ),modifyType );
984        }
985
986        /**
987         * 【TAG】リクエスト情報の クォーティション(') 存在チェックを実施するかどうか[true/false]を設定します
988         *              (初期値:USE_SQL_INJECTION_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK}])。
989         *
990         * @og.tag
991         * SQLインジェクション対策の一つとして、暫定的ではありますが、SQLのパラメータに
992         * 渡す文字列にクォーティション(') を許さない設定にすれば、ある程度は防止できます。
993         * 数字タイプの引数には、 or 5=5 などのクォーティションを使用しないコードを埋めても、
994         * 数字チェックで検出可能です。文字タイプの場合は、必ず (')をはずして、
995         * ' or 'A' like 'A のような形式になる為、(')チェックだけでも有効です。
996         * (') が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。
997         * 初期値は、SystemData#USE_SQL_INJECTION_CHECK です。
998         *
999         * @og.rev 4.0.0.0 (2005/08/31) 新規追加
1000         *
1001         * @param   flag クォーティションチェック [true:する/それ以外:しない]
1002         */
1003        public void setQuotCheck( final String flag ) {
1004                quotCheck = nval( getRequestParameter( flag ),quotCheck );
1005        }
1006
1007        /**
1008         * 【TAG】リクエスト情報の HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します
1009         *              (初期値:USE_XSS_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK}])。
1010         *
1011         * @og.tag
1012         * クロスサイトスクリプティング(XSS)対策の一環としてless/greater than signについてのチェックを行います。
1013         * (&gt;&lt;) が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。
1014         * (初期値:システム定数のUSE_XSS_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK}])
1015         *
1016         * @og.rev 5.0.0.2 (2009/09/15) 新規追加
1017         *
1018         * @param       flag    XSSチェック [true:する/false:しない]
1019         * @see         org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK
1020         */
1021        public void setXssCheck( final String flag ) {
1022                xssCheck = nval( getRequestParameter( flag ),xssCheck );
1023        }
1024
1025        /**
1026         * 【TAG】PLSQL/SQL処理エラーの時に処理を中止するかどうか[true/false]を設定します(初期値:true)。
1027         *
1028         * @og.tag
1029         * false(中止しない)に設定する場合、後続処理では、{&#064;DB.ERR_CODE}の値により、
1030         * PLSQL/SQLの異常/正常終了によって分岐処理は可能となります。
1031         * 初期値は、true(中止する)です。
1032         *
1033         * @og.rev 4.3.3.0 (2008/09/22) 新規追加
1034         *
1035         * @param   flag  [true:中止する/false:中止しない]
1036         */
1037        public void setStopError( final String flag ) {
1038                stopError = nval( getRequestParameter( flag ),stopError );
1039        }
1040        
1041        /**
1042         * 【TAG】PLSQL/SQL処理エラーの時にエラーを画面表示するか[true/false]を設定します(初期値:true)。
1043         *
1044         * @og.tag
1045         * false(表示しない)に設定する場合、後続処理では、{&#064;DB.ERR_MSG}の値により、
1046         * 本来表示されるはずだったメッセージを取得可能です。
1047         * stopErrorと併用して、JSON形式でエラーを返す場合等に利用します。
1048         * 初期値は、true(表示する)です。
1049         * ※false指定の場合は件数や、overFlowメッセージ等も表示されなくなります。
1050         *
1051         * @og.rev 5.9.26.1 (2017/11/10) 新規追加
1052         *
1053         * @param   flag  [true:表示する/false:表示しない]
1054         */
1055        public void setDispError( final String flag ) {
1056                dispError = nval( getRequestParameter( flag ),dispError );
1057        }
1058        
1059
1060        /**
1061         * 引数の SQL 文を EXPLAIN PLAN します。
1062         *
1063         * ここでは、以下の処理を行います。
1064         * 1.引数の SQL 文を画面に表示します。
1065         * 2.引数の SQL 文を EXPLAIN PLAN した結果を、画面に表示します。
1066         * なお、この処理は、ORACLE 専用処理です。
1067         *
1068         * @og.rev 3.8.5.3 (2006/08/07) 新規追加
1069         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
1070         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
1071         * @og.rev 5.5.3.4 (2012/06/19) getUserInfo は、キー部分だけで処理します。
1072         *
1073         * @param   sql         EXPLAIN PLANするSQL 文
1074         * @param   tran        Transactionオブジェクト
1075         *
1076         * @return トレース結果の文字列
1077         */
1078//      private String traceQuery( final String sql ) {
1079        private String traceQuery( final String sql , final Transaction tran ) {
1080//              ApplicationInfo appInfo = getApplicationInfo();
1081
1082//              String userId = getUserInfo( "USER.ID" ) ;
1083                String userId = getUserInfo( "ID" ) ;                   // 5.5.3.4 (2012/06/19) getUserInfo は、キー部分だけで処理します。
1084
1085                String[] arg1 = new String[] { userId };
1086//              DBUtil.dbExecute( "DELETE FROM PLAN_TABLE WHERE STATEMENT_ID = ?",arg1,appInfo,dbid );
1087                DBUtil.dbExecute( "DELETE FROM PLAN_TABLE WHERE STATEMENT_ID = ?",arg1,tran,dbid );             // 5.1.9.0 (2010/08/01)
1088
1089                String explan1 = "EXPLAIN PLAN SET STATEMENT_ID = '" + userId + "' FOR " + sql ;
1090//              DBUtil.dbExecute( explan1,null,appInfo,dbid );
1091                DBUtil.dbExecute( explan1,null,tran,dbid );             // 5.1.9.0 (2010/08/01)
1092
1093                String[] arg2 = new String[] { userId,userId,userId };
1094//              String explan2 = "SELECT LEVEL,LPAD(' ',LEVEL,' ') || RTRIM( OPERATION ) || ' ' ||"
1095//                                              + " RTRIM( OPTIONS )   || ' ' || RTRIM( OBJECT_NAME )"
1096//                                              + " FROM PLAN_TABLE"
1097//                                              + " WHERE STATEMENT_ID = ?"
1098//                                              + " CONNECT BY PRIOR ID = PARENT_ID"
1099//                                              + "         AND STATEMENT_ID = ?"
1100//                                              + " START WITH ID = 0"
1101//                                              + "         AND STATEMENT_ID = ?" ;
1102                String explan2 = "select LEVEL as LVL"
1103                                                        + ",lpad(' ',LEVEL,' ') || rtrim( OPERATION ) || ' ' || rtrim( OPTIONS ) || ' ' || rtrim( OBJECT_NAME ) as EXECUTION_PLAN"
1104                                                        + ",OBJECT_NAME                 as OBJ_NAME"
1105                                                        + ",DECODE(INSTR(OBJECT_TYPE,' '),0,OBJECT_TYPE,SUBSTR(OBJECT_TYPE,1,INSTR(OBJECT_TYPE,' ')-1)) as OBJ_TYPE"
1106                                                        + ",OPTIMIZER                   as OPT"
1107                                                        + ",COST                                as CST"
1108                                                        + ",CARDINALITY                 as CARD"
1109                                                        + ",BYTES                               as BYTE"
1110                                                        + ",ACCESS_PREDICATES   as ACCS"
1111                                                        + ",FILTER_PREDICATES   as FILTER"
1112                                                + " from PLAN_TABLE"
1113                                                + " where STATEMENT_ID = ?"
1114                                                + " start with ID = 0"
1115                                                + "       and STATEMENT_ID = ?"
1116                                                + " connect by prior ID = PARENT_ID"
1117                                                + "       and STATEMENT_ID = ?" ;
1118//              String[][] plan = DBUtil.dbExecute( explan2,arg2,appInfo,dbid );
1119//              String[][] plan = DBUtil.dbExecute( explan2,arg2,tran,dbid );                   // 5.1.9.0 (2010/08/01)
1120
1121//              StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
1122//              buf.append( "<pre>" ).append( sql ).append( "</pre>" ).append( HybsSystem.BR );
1123//              buf.append( "<table>" );
1124//              buf.append( "<tr  class=\"row_h\"><th>LEVEL</th><th>EXECUTION_PLAN</th></tr>" );
1125//              for( int i=0; i<plan.length; i++ ) {
1126//                      buf.append( "<tr class=\"row_" ).append( i%2 ).append( "\">" );
1127//                      buf.append( "<td>" ).append( plan[i][0] ).append( "</td>" );
1128//                      buf.append( "<td><pre>" ).append( plan[i][1] ).append( "</td></tr>" );
1129//              }
1130//              buf.append( "</table>" ).append( HybsSystem.BR );
1131
1132                String[][] plan = DBUtil.dbExecute( explan2,arg2,tran,dbid,true );                      // 5.5.3.4 (2012/06/19) ヘッダー情報も同時に取得する。
1133
1134                StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
1135                buf.append( "<pre>" ).append( sql ).append( "</pre>" ).append( HybsSystem.BR );
1136                buf.append( "<table>" );
1137                // 1行目のヘッダーの出力
1138                int colsize = plan[0].length;
1139                buf.append( "<tr class=\"row_h\">" );
1140                for( int j=0; j<colsize; j++ ) {
1141                        buf.append( "<th>" ).append( plan[0][j] ).append( "</th>" );
1142                }
1143                buf.append( "</tr>" );
1144
1145                for( int i=1; i<plan.length; i++ ) {
1146                        buf.append( "<tr class=\"row_" ).append( i%2 ).append( "\">" );
1147                        for( int j=0; j<colsize; j++ ) {
1148                                if( j==1 ) {
1149                                        buf.append( "<td><pre>" ).append( plan[i][1] ).append( "</pre></td>" );
1150                                }
1151                                else {
1152                                        buf.append( "<td>" ).append( plan[i][j] ).append( "</td>" );
1153                                }
1154                        }
1155                        buf.append( "</tr>" );
1156                }
1157                buf.append( "</table>" ).append( HybsSystem.BR );
1158                return buf.toString();
1159        }
1160
1161        /**
1162         * 【TAG】(通常使いません)タグで処理される処理がメインとなるトランザクション処理かどうかを指定します(初期値:true)。
1163         *
1164         * @og.tag
1165         * この値は、ファイルダウンロード処理に影響します。この値がtrueに指定された時にcommitされたDBTableModelが
1166         * ファイルダウンロードの対象の表になります。
1167         *
1168         * このパラメーターは、通常、各タグにより実装され、ユーザーが指定する必要はありません。
1169         * 但し、1つのJSP内でDBTableModelが複数生成される場合に、前に処理したDBTableModelについてファイルダウンロードをさせたい
1170         * 場合は、後ろでDBTableModelを生成するタグで、明示的にこの値をfalseに指定することで、ファイルダウンロード処理の対象から
1171         * 除外することができます。
1172         *
1173         * @og.rev 5.1.6.0 (2010/05/01) 新規作成
1174         *
1175         * @param  flag メイントランザクションかどうか
1176         */
1177        public void setMainTrans( final String flag ) {
1178                isMainTrans = nval( getRequestParameter( flag ),isMainTrans );
1179        }
1180
1181        /**
1182         * 【TAG】 処理時間(queryTime)などの情報出力[true:有効/false:無効]を指定します(初期値:true)。
1183         *
1184         * @og.tag
1185         * Query で、検索する場合に、処理時間(queryTime)などの情報を出力していますが、
1186         * ViewForm で、CustomData などの 非HTML表示ビューを使用する場合、データとして、
1187         * 紛れ込んでしまうため、出力を抑制する必要があります。
1188         * true(有効)にすると、これらのHTMLが出力されます。false にすると、出力されません。
1189         * 初期値は、true(有効) です。
1190         *
1191         * @og.rev 5.3.5.0 (2011/05/01) 新規追加
1192         *
1193         * @param  useTag  情報出力の有効/無効を指定 [true:有効/false:無効]
1194         */
1195        public void setUseBeforeHtmlTag( final String useTag ) {
1196                useBeforeHtmlTag = nval( getRequestParameter( useTag ),useBeforeHtmlTag );
1197        }
1198
1199        /**
1200         * シリアライズ用のカスタムシリアライズ書き込みメソッド
1201         *
1202         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
1203         * @serialData 一部のオブジェクトは、シリアライズされません。
1204         *
1205         * @param       strm    ObjectOutputStreamオブジェクト
1206         * @throws IOException  入出力エラーが発生した場合
1207         */
1208        private void writeObject( final ObjectOutputStream strm ) throws IOException {
1209                strm.defaultWriteObject();
1210        }
1211
1212        /**
1213         * シリアライズ用のカスタムシリアライズ読み込みメソッド
1214         *
1215         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
1216         *
1217         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
1218         * @serialData 一部のオブジェクトは、シリアライズされません。
1219         *
1220         * @param       strm    ObjectInputStreamオブジェクト
1221         * @see #release2()
1222         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
1223         * @throws ClassNotFoundException       クラスを見つけることができなかった場合
1224         */
1225        private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
1226                strm.defaultReadObject();
1227        }
1228
1229        /**
1230         * このオブジェクトの文字列表現を返します。
1231         * 基本的にデバッグ目的に使用します。
1232         *
1233         * @return このクラスの文字列表現
1234         */
1235        @Override
1236        public String toString() {
1237                return sql ;
1238
1239        //      return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
1240        //                      .println( "VERSION"                     ,VERSION                )
1241        //                      .println( "tableId"                     ,tableId                )
1242        //                      .println( "queryType"           ,queryType              )
1243        //                      .println( "dbid"                        ,dbid                   )
1244        //                      .println( "command"                     ,command                )
1245        //                      .println( "skipRowCount"        ,skipRowCount   )
1246        //                      .println( "maxRowCount"         ,maxRowCount    )
1247        //                      .println( "sql"                         ,sql                    )
1248        //                      .println( "displayMsg"          ,displayMsg             )
1249        //                      .println( "overflowMsg"         ,overflowMsg    )
1250        //                      .println( "executeCount"        ,executeCount   )
1251        //                      .println( "names"                       ,names                  )
1252        //                      .println( "outMessage"          ,outMessage             )
1253        //                      .println( "trace"                       ,trace                  )
1254        //                      .println( "errCode"                     ,errCode                )
1255        //                      .println( "stopZero"            ,stopZero               )
1256        //                      .println( "quotCheck"           ,quotCheck              )
1257        //                      .println( "dyStart"                     ,dyStart                )
1258        //                      .println( "checkNames"          ,checkNames             )
1259        //                      .println( "Other..."            ,getAttributes().getAttribute() )
1260        //                      .fixForm().toString() ;
1261        }
1262}