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.File;
021import java.io.FileOutputStream;
022import java.io.IOException;
023import java.io.ObjectInputStream;
024import java.io.ObjectOutputStream;
025import java.io.PrintWriter;
026import java.sql.CallableStatement;
027import java.sql.Connection;
028import java.sql.ResultSet;
029import java.sql.ResultSetMetaData;
030import java.sql.SQLException;
031import java.sql.Statement;
032import java.sql.Types;
033import java.util.Locale ;
034import java.util.Map;
035import java.util.zip.ZipEntry;
036import java.util.zip.ZipOutputStream;
037
038import org.opengion.fukurou.db.Transaction;
039import org.opengion.fukurou.db.TransactionReal;
040import org.opengion.fukurou.model.FileOperation;
041import org.opengion.fukurou.util.Closer ;
042import org.opengion.fukurou.util.ErrorMessage;
043import org.opengion.fukurou.util.FileUtil;
044import org.opengion.fukurou.util.StringUtil;
045import org.opengion.hayabusa.common.HybsSystem;
046import org.opengion.hayabusa.common.HybsSystemException;
047import org.opengion.hayabusa.db.DBErrMsg;
048import org.opengion.hayabusa.io.HybsFileOperationFactory;
049import org.opengion.hayabusa.resource.GUIInfo;
050import org.opengion.hayabusa.resource.ResourceManager;
051
052import oracle.jdbc.OracleCallableStatement;                     // CURSOR が残る
053import oracle.jdbc.OracleTypes;                                         // CURSOR が残る
054// import java.sql.Array;                                                       // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ) 対応。oracle.sql.ARRAY の置き換え
055import oracle.sql.ARRAY;                                                        // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ) 対応
056import oracle.sql.ArrayDescriptor;                                      // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ) 対応
057// import oracle.jdbc.OracleConnection;                         // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ) 対応
058
059/**
060 * SELECT文を直接実行して、指定のファイルに出力するタグです。
061 *
062 * 中間の、データ(DBTableModel)を作成しないため、余計なメモリを取らず、
063 * 高速にデータを抜き出すことが可能です。
064 * 一方、抜き出すデータは生データのため、データの再利用等、システム的な
065 * 使用を想定しています。
066 * JDBCErrMsg 形式のPL/SQL をコールして、その検索結果(カーソル)を抜きこともできます。
067 *
068 * ※ このタグは、Transaction タグの対象です。
069 *
070 * @og.formSample
071 * ●形式:<og:directWriteTable filename="[・・・]" ・・・ >SELECT * FROM ZYXX </og:directWriteTable >
072 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
073 *
074 * ●Tag定義:
075 *   <og:directWriteTable
076 *       fileURL            【TAG】保存先ディレクトリ名を指定します (初期値:FILE_URL[=filetemp/])
077 *       filename           【TAG】ファイルを作成するときのファイル名をセットします(初期値:システムパラメータのFILE_FILENAME)
078 *       zipFilename        【TAG】ZIPファイルを作成するときのZIPファイル名をセットします(初期値:filename + ".zip")
079 *       encode             【TAG】ファイルを作成するときのファイルエンコーディング名をセットします (初期値:FILE_ENCODE[=UnicodeLittle])
080 *       fileAppend         【TAG】追加モードで書き込むかどうか[true/false]を指定します(初期値:false[通常モード])
081 *       zip                【TAG】結果をファイルに出力するときに、ZIPで圧縮するかどうか[true/false]を指定します(初期値:false)
082 *       separator          【TAG】可変長ファイルを作成するときの項目区切り文字をセットします (初期値:TAB_SEPARATOR[= ])
083 *       useHeader          【TAG】ヘッダーを書き込むかどうか[true/false]を指定します(初期値:true)
084 *       displayMsg         【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します(初期値:MSG0033[ 件検索しました])
085 *       notfoundMsg        【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])
086 *       fetchSize          【TAG】(通常は使いません)データのフェッチサイズを指定します(初期値:100)
087 *       names              【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します
088 *       queryType          【TAG】Query を発行する為のクラスID(JDBC,JDBCErrMsg)を指定します({@og.doc03Link queryType 初期値:JDBC})
089 *       dbid               【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT)
090 *       useNumber          【TAG】行番号を出力するかどうか(初期値:true)
091 *       storageType            【TAG】保存先ストレージタイプを指定します(初期値:CLOUD_TARGET)
092 *       bucketName                     【TAG】保存先バケット名を指定します(初期値:CLOUD_BUCKET)
093 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
094 *   >   ... Body ...
095 *   </og:directWriteTable>
096 *
097 * ●使用例
098 *     <og:directWriteTable
099 *         dbid        = "ORCL"               接続データベースID(初期値:DEFAULT)
100 *         separator   = ","                  ファイルの区切り文字(初期値:タブ)
101 *         fileURL     = "{@USER.ID}"    保存先ディレクトリ名
102 *         filename    = "{@filename}"   保存ファイル名
103 *         encode      = "UnicodeLittle"      保存ファイルエンコード名
104 *         useHeader   = "true"               保存ファイルにヘッダーを出力するかどうか
105 *         zip         = "true"               ZIPファイルに圧縮するかどうか
106 *         zipFilename = "Sample.zip"         ZIPファイルのファイル名
107 *         fileAppend  = "true"               ファイルを追加モードで登録するかどうか
108 *         displayMsg  = "MSG0033"            実行後の表示メッセージ
109 *         fetchSize   = "200"                DB検索する場合のフェッチするサイズ
110 *         storageType = "aws"                保存先のストレージタイプを指定します(初期値:CLOUD_STORAGE)
111 *         bucketName   = "mybucket001"         保存先のバケット名を指定します(初期値:CLOUD_BUCKET)
112 *     >
113 *         SELECT * FROM ZYXX 
114 *     </og:directWriteTable >
115 *
116 *     <og:directWriteTable
117 *         fileURL     = "{@USER.ID}"    保存先ディレクトリ名
118 *         filename    = "{@filename}"   保存ファイル名
119 *         names       = "AAA,BBB,CCC,・・・"    指定のキーに対応するリクエスト値を ARG_ARRAY にセットします。
120 *         queryType   = "JDBCErrMsg"         JDBCErrMsg 形式のPL/SQL をコールします。
121 *     >
122 *        { call PL/SQL(?,?,?,? ) } 
123 *     </og:directWriteTable >
124 *
125 * @og.rev 3.5.6.0 (2004/06/18) 新規作成
126 * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)の実行を追加
127 * @og.rev 5.10.9.0 (2019/03/01) oota クラウドストレージ対応。(Fileクラスを拡張)
128 * 
129 * @og.group ファイル出力
130 *
131 * @version  4.0
132 * @author   Kazuhiko Hasegawa
133 * @since    JDK5.0,
134 */
135public class DirectWriteTableTag extends CommonTagSupport {
136        //* このプログラムのVERSION文字列を設定します。   {@value} */
137        private static final String VERSION = "5.7.2.3 (2014/01/31)" ;
138
139        private static final long serialVersionUID = 572320140131L ;
140
141        private static final String TAB_SEPARATOR       = "\t" ;
142        private static final String errMsgId            = HybsSystem.ERR_MSG_KEY;
143
144        private final int DB_MAX_QUERY_TIMEOUT          = HybsSystem.sysInt( "DB_MAX_QUERY_TIMEOUT" ) ;
145//      private static final String ARG_ARRAY           = HybsSystem.sys( "ARG_ARRAY" ) ;
146//      private static final String ERR_MSG                     = HybsSystem.sys( "ERR_MSG" ) ;
147//      private static final String ERR_MSG_ARRAY       = HybsSystem.sys( "ERR_MSG_ARRAY" ) ;
148        private static final String ARG_ARRAY           = "ARG_ARRAY" ;
149        private static final String ERR_MSG                     = "ERR_MSG" ;
150        private static final String ERR_MSG_ARRAY       = "ERR_MSG_ARRAY" ;
151
152        // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
153//      private String  dbid            = "DEFAULT";
154        private String  dbid            = null;
155        private String  separator       = TAB_SEPARATOR;   // 項目区切り文字
156        private boolean useHeader       = true;         // ヘッダーの使用可否
157        private String  fileURL         = HybsSystem.sys( "FILE_URL" );
158        private String  filename        = HybsSystem.sys( "FILE_FILENAME" );   // ファイル名
159        private String  zipFilename     = null;         // ZIPファイル名
160        private String  sql                     = null;
161        private String  encode          = HybsSystem.sys( "FILE_ENCODE"   );   // ファイルエンコーディング  "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
162        private boolean fileAppend      = false;        // ファイルをAPPENDモードで出力するか
163        private boolean zip                     = false;        // ファイルをZIPするか
164//      private String  displayMsg      = "MSG0033";    //  件検索しました。
165        private String  displayMsg      = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
166        private String  notfoundMsg     = "MSG0077";    // 対象データはありませんでした。
167        private long    dyStart         = 0;    // 実行時間測定用のDIV要素を出力します。
168        private int             fetchSize       = 100 ; // フェッチする行数(初期値:100)
169        private boolean useNumber       = true;  // 5.5.7.1(2012/10/05) 行番号出力
170
171        // 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
172        private boolean queryType       = true; // ノーマルは、true/ JDBCErrMsg の時は、false
173        private String  names           = null; // 指定のリクエスト変数を、ARG_ARRAY にセットします。
174        private int             errCode         = ErrorMessage.OK;
175        private transient ErrorMessage errMessage = null;
176        private String  storageType     = null;                 // 5.10.9.0 (2019/03/01) クラウドストレージタイプ
177        private String  bucketName      = null;                 // 5.10.9.0 (2019/03/01) バケット名
178        
179        /**
180         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
181         *
182         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
183         */
184        @Override
185        public int doStartTag() {
186                dyStart = System.currentTimeMillis();           // 時間測定用
187                return( EVAL_BODY_BUFFERED );   // Body を評価する。( extends BodyTagSupport 時)
188        }
189
190        /**
191         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
192         *
193         * @og.rev 3.8.6.3 (2006/11/30) SQL 文の前後のスペースを取り除きます。
194         *
195         * @return      後続処理の指示(SKIP_BODY)
196         */
197        @Override
198        public int doAfterBody() {
199                sql = getBodyString();
200                if( sql == null || sql.length() == 0 ) {
201                        String errMsg = "BODY 部の検索用 Select文は、必須です。";
202                        throw new HybsSystemException( errMsg );
203                }
204                sql = sql.trim();
205                return(SKIP_BODY);                              // Body を評価しない
206        }
207
208        /**
209         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
210         *
211         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
212         * @og.rev 4.0.0.0 (2007/10/18) メッセージリソース統合( getResource().getMessage ⇒ getResource().getLabel )
213         * @og.rev 5.10.9.0 (2019/03/01) クラウドストレージ対応。
214         *
215         * @return      後続処理の指示
216         */
217        @Override
218        public int doEndTag() {
219                debugPrint();           // 4.0.0 (2005/02/28)
220
221                PrintWriter pw = null;
222                final int executeCount;
223                try {
224                        if( zip ) {
225                                String directory = HybsSystem.url2dir( fileURL );
226
227                                if( zipFilename == null ) { zipFilename = filename + ".zip"; }
228                                ZipOutputStream gzip = null;
229                                try {
230                                        gzip = new ZipOutputStream(
231                                                                new FileOutputStream(
232                                                                                StringUtil.urlAppend( directory,zipFilename )));
233                                        gzip.putNextEntry( new ZipEntry( filename ) );
234                                        pw = new PrintWriter( gzip );
235                                        executeCount = create( pw ) ;
236
237                                        pw.flush();
238                                        gzip.closeEntry();
239                                        gzip.finish() ;
240                                }
241                                finally {
242                                        Closer.ioClose( gzip );         // 4.0.0 (2006/01/31) close 処理時の IOException を無視
243                                }
244                        }
245                        else {
246                                pw = getPrintWriter();
247                                executeCount = create( pw );
248                        }
249                } catch( IOException ex ) {
250                        String errMsg = "Error in DirectWriteTableTag: " + toString();
251                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
252                } finally {
253                        Closer.ioClose( pw );           // 4.0.0 (2006/01/31) close 処理時の IOException を無視
254                }
255
256                // 5.10.9.0 (2019/03/01) ADD クラウドストレージ利用の場合はアップロードする
257                String directory = HybsSystem.url2dir( fileURL );
258                String trgFileName;
259                if(zip) {
260                        trgFileName = filename + ".zip";
261                }else {
262                        trgFileName = filename;
263                }
264                FileOperation cloudFile = HybsFileOperationFactory.create(storageType, bucketName, directory, trgFileName);
265                if(!cloudFile.isLocal()) {
266                        File localFile = new File(directory, trgFileName);
267                        FileUtil.copy(localFile, cloudFile);
268                        localFile.delete();
269                }
270                
271                // 3.6.1.0 (2005/01/05) 検索結果の件数を、"DB.COUNT" キーでリクエストにセットする。
272                setRequestAttribute( "DB.COUNT"   , String.valueOf( executeCount ) );
273                setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
274
275                StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_SMALL );
276
277                // 実行件数の表示
278//              boolean useStatusBar = HybsSystem.sysBool( "VIEW_USE_DISPLAY_MSG" );
279//              if( useStatusBar && executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
280                if( executeCount > 0 && displayMsg != null && displayMsg.length() > 0 ) {
281                        buf.append( executeCount );
282//                      buf.append( getResource().getMessage( displayMsg ) );
283                        buf.append( getResource().getLabel( displayMsg ) );
284                        buf.append( HybsSystem.BR );
285                }
286                else if( executeCount == 0 && notfoundMsg != null && notfoundMsg.length() > 0 ) {
287//                      buf.append( getResource().getMessage( notfoundMsg ) );
288                        buf.append( getResource().getLabel( notfoundMsg ) );
289                        buf.append( HybsSystem.BR );
290                }
291
292                // 3.6.1.0 (2005/01/05) TaglibUtil.makeHTMLErrorTable メソッドを利用
293                String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
294                if( err != null && err.length() > 0 ) {
295                        buf.append( err );
296                        setSessionAttribute( errMsgId,errMessage );
297                }
298                else {
299                        removeSessionAttribute( errMsgId );
300                }
301
302                jspPrint( buf.toString() );
303
304                // 時間測定用の DIV 要素を出力
305                long dyTime = System.currentTimeMillis()-dyStart;
306                jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );      // 3.5.6.3 (2004/07/12)
307
308                // 3.6.1.0 (2005/01/05) 警告時に停止していましたが、継続処理させます。
309                int rtnCode = EVAL_PAGE;
310                if( errCode >= ErrorMessage.NG )  {  // 異常
311                        rtnCode = SKIP_PAGE;
312                }
313
314                // 4.0.0 (2005/01/31) セキュリティチェック(データアクセス件数登録)
315                GUIInfo guiInfo = (GUIInfo)getSessionAttribute( HybsSystem.GUIINFO_KEY );
316                if( guiInfo != null ) { guiInfo.addReadCount( executeCount,dyTime,sql ); }
317
318                return( rtnCode );
319        }
320
321        /**
322         * タグリブオブジェクトをリリースします。
323         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
324         *
325         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
326         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
327         * @og.rev 5.5.7.1 (2012/10/05) useNumber追加
328         * @og.rev 5.10.9.0 (2019/03/01) storageType,bucketName属性を追加
329         */
330        @Override
331        protected void release2() {
332                super.release2();
333                separator       = TAB_SEPARATOR;   // 項目区切り文字
334                fileURL         = HybsSystem.sys( "FILE_URL" );
335                filename        = HybsSystem.sys( "FILE_FILENAME" );   // ファイル名
336                zipFilename     = null;         // ZIPファイル名
337                sql                     = null;
338                encode          = HybsSystem.sys( "FILE_ENCODE" );   // ファイルエンコーディング  "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
339                fileAppend      = false;        // ファイルをAPPENDモードで出力するか
340                zip                     = false;        // ファイルをZIPするか
341//              displayMsg      = "MSG0033";    //  件検索しました。
342                displayMsg      = HybsSystem.sys( "VIEW_DISPLAY_MSG" );
343                notfoundMsg     = "MSG0077";    // 対象データはありませんでした。
344//              dbid            = "DEFAULT";
345                dbid            = null;
346                fetchSize       = 100 ; // フェッチする行数(初期値:0 参考にしない)
347                dyStart         = 0;
348                queryType       = true; // ノーマルは、true/ JDBCErrMsg の時は、false
349                names           = null; // 指定のリクエスト変数を、ARG_ARRAY にセットします。
350                errCode         = ErrorMessage.OK;
351                errMessage      = null;
352                useNumber       = true; // 5.5.7.1 (2012/10/05)
353                storageType             = null;         // 5.10.9.0 (2019/03/01)
354                bucketName              = null;         // 5.10.9.0 (2019/03/01)
355        }
356
357        /**
358         * 実オブジェクトを生成して,OutputStream に書き込みます。
359         *
360         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
361         * @og.rev 3.8.6.0 (2006/09/29) ヘッダーにラベルを出力するように修正
362         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
363         * @og.rev 4.3.4.3 (2008/12/22) (Oracle11gDriver対応)PL/SQLコールの場合に、"クローズされた文です。"のエラーが発生する問題に対応
364         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応
365         * @og.rev 5.2.2.0 (2010/11/01) 改行を含む場合は、ダブルクオートを強制的に前後に追加する。
366         * @og.rev 5.2.2.0 (2010/11/01) ダブルクオートを含む場合は、その直前にダブルクオートを強制的に追加する。
367         * @og.rev 5.3.0.0 (2010/12/01) executeCall メソッドの引数見直し
368         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
369         * @og.rev 5.5.7.1 (2012/10/05) useNumberの追加
370         *
371         * @param   out PrintWriterオブジェクト
372         *
373         * @return      検索件数
374         */
375        private int create( final PrintWriter out )  {
376                final int executeCount;
377                Statement stmt = null;
378                CallableStatement callStmt = null; // 4.3.4.3 (2008/12/22)
379                ResultSet resultSet = null ;
380                boolean errFlag = true;
381//              Connection conn  = null;
382                Transaction tran = null;        // 5.1.9.0 (2010/08/01) Transaction 対応
383                try {
384                        // 5.1.9.0 (2010/08/01) Transaction 対応
385                        TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class );
386                        if( tranTag == null ) {
387//                              tran = new TransactionReal( dbid,getApplicationInfo() );
388                                tran = new TransactionReal( getApplicationInfo() );             // 5.3.7.0 (2011/07/01) 引数変更
389                        }
390                        else {
391                                tran = tranTag.getTransaction();
392                        }
393//                      conn = ConnectionFactory.connection( dbid,getApplicationInfo() );       // 3.8.7.0 (2006/12/15)
394
395                        Connection conn = tran.getConnection( dbid );                   // 5.1.9.0 (2010/08/01) Transaction 対応
396                        // 3.6.1.0 (2005/01/05)
397                        if( queryType ) {               // JDBC 通常の SELECT 文
398                                stmt = conn.createStatement();
399                                if( fetchSize > 0 ) { stmt.setFetchSize( fetchSize ); }
400                                resultSet = stmt.executeQuery( sql );
401                        }
402                        else {                                  // PL/SQL Call 文
403                                String[] values = null;
404                                if( names != null ) {
405                                        String[] nameArray = StringUtil.csv2Array( names );
406                                        values = getRequest( nameArray );
407                                }
408                                callStmt  = conn.prepareCall( sql );
409//                              resultSet = executeCall( conn,callStmt,sql,values );    // 4.3.4.3 (2008/12/22)
410                                resultSet = executeCall( conn,callStmt,values );                // 5.3.0.0 (2010/12/01)
411                        }
412                        if( resultSet == null ) { return 0; }
413
414                        ResultSetMetaData metaData  = resultSet.getMetaData();
415                        int numberOfColumns =  metaData.getColumnCount();
416
417                        // ヘッダー部の出力
418                        if( useHeader && numberOfColumns > 0 ) {
419                                StringBuilder headName  = new StringBuilder();
420                                StringBuilder headLabel = new StringBuilder();
421                                headName.append( "#Name" );
422                                headLabel.append( "#Label" );
423                                String clm ;
424                                ResourceManager resource = getResource();
425                                for(int column = 1; column <= numberOfColumns; column++) {
426                                        clm = (metaData.getColumnLabel(column)).toUpperCase(Locale.JAPAN);
427                                        headName.append( TAB_SEPARATOR ).append( clm );
428                                        headLabel.append( TAB_SEPARATOR ).append( resource.getLabel( clm ) );
429                                }
430                                out.println( headName.toString() );
431                                out.println( headLabel.toString() );
432                        }
433
434                        int rowNo = 0;
435                        Object obj ;
436                        while( resultSet.next() ) {
437                                if( useNumber ){ // 5.5.7.1 (2012/10/05)
438                                        out.print( rowNo );                             // 行番号
439                                }
440                                for(int column = 1; column <= numberOfColumns; column++) {
441                                        if( column == 1 && !useNumber && !useHeader ){ // 5.5.7.1 (2012/10/05)
442                                                //この場合だけセパレータ出力しない
443                                        }
444                                        else{
445                                                out.print( separator );
446                                        }
447                                        obj = resultSet.getObject(column);
448                                        if( obj != null ) {
449//                                              out.print( obj );
450                                                // 5.2.2.0 (2010/11/01) 改行、ダブルクオート等の処理
451                                                String sval = obj.toString();
452                                                if( sval.indexOf( '"' ) >= 0 ) { sval = sval.replaceAll( "\"" ,"\"\"" ) ; }
453                                                if( sval.indexOf( HybsSystem.CR ) >= 0 ) {
454                                                        sval = "\"" + sval + "\"" ;
455                                                }
456                                                out.print( sval );
457                                        }
458                                }
459                                out.println();
460                                rowNo++ ;
461                        }
462                        executeCount = rowNo ;
463                        errFlag = false;                // エラーではない
464                }
465                catch ( SQLException ex ) {             // 3.6.1.0 (2005/01/05)
466                        String errMsg = "データベース処理を実行できませんでした。"
467                                                 + HybsSystem.CR + stmt + HybsSystem.CR
468                                                 + "err=[" + ex.getSQLState() + "]"
469                                                 + ex.getMessage();
470                        throw new HybsSystemException( errMsg,ex );
471                }
472                finally {
473                        Closer.resultClose( resultSet );
474                        Closer.stmtClose( stmt );
475                        Closer.stmtClose( callStmt );   // 4.3.4.3 (2008/12/22)
476                        if( tran != null ) {                            // 5.5.2.6 (2012/05/25) findbugs対応
477                                tran.close( errFlag );                  // 5.1.9.0 (2010/08/01) Transaction 対応
478                        }
479//                      if( errFlag ) { ConnectionFactory.remove( conn,dbid ); }        // 削除
480//                      else {                  ConnectionFactory.close( conn,dbid );  }        // 返却
481//                      conn = null;
482                }
483
484                return executeCount ;
485        }
486
487        /**
488         * 引数配列付のクエリーを実行します。
489         * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。
490         * これは、CallableStatement を用いて、データベース検索処理を行います。
491         * {call TYPE3B01.TYPE3B01(?,?,?,?)} で、4番目の引数には、
492         * names で指定したリクエスト情報が、ARG_ARRAY 配列に順次セットされます。
493         * 使用する場合は、一旦わかり易い変数に受けて利用してください。
494         * 呼び出す PL/SQL では、検索系PL/SQL です。
495         *
496         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
497         * @og.rev 4.3.4.3 (2008/12/22) (Oracle11gDriver対応)PL/SQLコールの場合に、"クローズされた文です。"のエラーが発生する問題に対応
498         * @og.rev 5.3.0.0 (2010/12/01) executeCall メソッドの引数見直し
499         * @og.rev 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応
500         * @og.rev 5.7.2.3 (2014/01/31) Oracle11g(11.2.0.3のドライバ)対応は、Ver5 では行わない(戻す)。
501         *
502         * @param       conn            コネクション
503         * @param   callStmt    コーラブルステートメント
504         * @param   args                オブジェクトの引数配列
505         *
506         * @return      結果オブジェクト
507         */
508//      private ResultSet executeCall( final Connection conn,final CallableStatement callStmt,final String sql,final String[] args ) throws SQLException {
509        private ResultSet executeCall( final Connection conn,final CallableStatement callStmt,final String[] args ) throws SQLException {
510//              CallableStatement callStmt = null ; // 4.3.4.3 (2008/12/22)
511                ResultSet resultSet = null;
512//              try {
513//                      callStmt  = conn.prepareCall( sql );
514                        callStmt.setQueryTimeout( DB_MAX_QUERY_TIMEOUT );
515                        if( fetchSize > 0 ) { callStmt.setFetchSize( fetchSize ); }
516                        Map<String,Class<?>> map = conn.getTypeMap();
517                        try {
518                                map.put( ERR_MSG,Class.forName( "org.opengion.hayabusa.db.DBErrMsg" ) );
519                        }
520                        catch( ClassNotFoundException ex ) {
521                                String errMsg = "org.opengion.hayabusa.db.DBErrMsg クラスが見つかりません。" + HybsSystem.CR
522                                                + ex.getMessage();                      // // 5.1.8.0 (2010/07/01) errMsg 修正
523                                throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
524                        }
525
526                        // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応 http://docs.oracle.com/cd/E28389_01/web.1111/b60995/thirdparty.htm
527                        ArrayDescriptor sd = ArrayDescriptor.createDescriptor( ARG_ARRAY, conn );
528                        ARRAY newArray = new ARRAY( sd,conn,StringUtil.rTrims( args ) );
529//                      Array newArray = ((OracleConnection)conn).createOracleArray( ARG_ARRAY, StringUtil.rTrims( args ));             // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応
530
531                        callStmt.registerOutParameter(1, Types.INTEGER);
532                        callStmt.registerOutParameter(2, OracleTypes.ARRAY,ERR_MSG_ARRAY);      // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応
533//                      callStmt.registerOutParameter(2, Types.ARRAY,ERR_MSG_ARRAY);            // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応
534                        callStmt.registerOutParameter(3, OracleTypes.CURSOR);
535                        ((OracleCallableStatement)callStmt).setARRAY( 4,newArray );                     // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応
536//                      callStmt.setArray( 4,newArray );                                                                        // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応
537
538                        callStmt.execute();
539
540                        errCode = callStmt.getInt(1);
541
542                        if( errCode < ErrorMessage.NG ) {            // 異常以外の場合
543                                resultSet = ((OracleCallableStatement)callStmt).getCursor(3);
544                        }
545                        if( errCode > ErrorMessage.OK ) {            // 正常以外の場合
546                                ARRAY rtn3 = ((OracleCallableStatement)callStmt).getARRAY(2);   // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応
547//                              Array rtn3 = callStmt.getArray(2);                                                              // 5.7.2.2 (2014/01/24) Oracle11g(11.2.0.3のドライバ)対応
548                                Object[] rtnval3 = (Object[])rtn3.getArray();
549                                errMessage = new ErrorMessage( "Query_JDBCErrMsg Error!!" );
550                                for( int i=0; i<rtnval3.length; i++ ) {
551                                        DBErrMsg er = (DBErrMsg)rtnval3[i];
552                                        if( er == null ) { break; }
553                                        errMessage.addMessage( er.getErrMsg() );
554                                }
555                        }
556//              }
557//              finally {
558//                      Closer.stmtClose( callStmt );
559//                      callStmt = null;
560//              }
561                return resultSet;
562        }
563
564        /**
565         * PrintWriter を取得します。
566         *
567         * ここでは、一般的なファイル出力を考慮した PrintWriter を作成します。
568         *
569         * @og.rev 3.7.1.1 (2005/05/23) フォルダがない場合は、複数階層分のフォルダを自動で作成します。
570         * @og.rev 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用。
571         * @og.rev 5.6.1.0 (2013/02/01) 3.7.1.1のコメントに入っているが対応されていないのでフォルダ作成追加
572         * @og.rev 5.10.9.0 (2019/03/01) クラウドストレージ対応を追加。
573         *
574         * @return       出力用PrintWriterオブジェクト
575         */
576        private PrintWriter getPrintWriter() {
577                if( filename == null ) {
578                        String errMsg = "ファイル名がセットされていません。";
579                        throw new HybsSystemException( errMsg );
580                }
581                String directory = HybsSystem.url2dir( fileURL );
582                
583                // 5.6.1.0 (2013/02/01)
584                // 5.10.9.0 (2019/03/01) MODIFY
585                // File dir = new File(directory);
586                File dir = HybsFileOperationFactory.create(storageType, bucketName, directory);
587                if( ! dir.exists() && ! dir.mkdirs() ) {
588                        String errMsg = "ディレクトリの作成に失敗しました。[" + directory + "]";
589                        throw new HybsSystemException( errMsg );
590                }
591
592
593                // ※ 注意 StringUtil.urlAppend を組み込んでいる意図が不明。一旦削除していますが、注意
594                // 3.8.0.0 (2005/06/07) FileUtil#getPrintWriter を利用。
595        //      out = FileUtil.getPrintWriter( StringUtil.urlAppend( directory,filename ),fileAppend,encode);
596
597//              処理を簡素化します。
598//              PrintWriter out = FileUtil.getPrintWriter( new File( directory,filename ),encode,fileAppend );
599//              return out ;
600                
601                // 5.10.9.0 (2019/03/01) ADD クラウドストレージ利用、fileAppend、かつファイルが存在する場合はダウンロードする。
602                FileOperation cloudFile = HybsFileOperationFactory.create(storageType, bucketName, directory, filename);
603                if(!cloudFile.isLocal() && fileAppend && cloudFile.isFile()) {
604                        File localFile = new File(directory, filename);
605                        localFile.delete();
606                        FileUtil.copy(cloudFile, localFile);
607                }
608                
609                return FileUtil.getPrintWriter( new File( directory,filename ),encode,fileAppend );
610        }
611
612        /**
613         * 名称配列を元に、リクエスト情報のデータを取得します。
614         *
615         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
616         *
617         * @param       nameArray       キーとなる名称の配列
618         *
619         * @return      そのリクエスト情報
620         */
621        private String[] getRequest( final String[] nameArray ) {
622                String[] rtn = new String[nameArray.length];
623
624                for( int i=0; i<rtn.length; i++ ) {
625                        rtn[i] = getRequestValue( nameArray[i] );
626                }
627
628                return rtn;
629        }
630
631        /**
632         * 【TAG】(通常は使いません)検索時のDB接続IDを指定します(初期値:DEFAULT)。
633         *
634         * @og.tag
635         *   検索時のDB接続IDを指定します。初期値は、DEFAULT です。
636         *
637         * @param       id データベース接続ID
638         */
639        public void setDbid( final String id ) {
640                dbid = nval( getRequestParameter( id ),dbid );
641        }
642
643        /**
644         * 【TAG】可変長ファイルを作成するときの項目区切り文字をセットします
645         *              (初期値:TAB_SEPARATOR[={@og.value #TAB_SEPARATOR}])。
646         *
647         * @og.tag 可変長ファイルを作成するときの項目区切り文字をセットします。
648         * (初期値:ローカル定義のTAB_SEPARATOR[={@og.value #TAB_SEPARATOR}])。
649         *
650         * @param   sep 項目区切り文字
651         * @see         #TAB_SEPARATOR
652         */
653        public void setSeparator( final String sep ) {
654                separator = nval( getRequestParameter( sep ),TAB_SEPARATOR );
655        }
656
657        /**
658         * 【TAG】保存先ディレクトリ名を指定します
659         *              (初期値:FILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。
660         *
661         * @og.tag
662         * この属性で指定されるディレクトリに、ファイルをセーブします。
663         * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、
664         * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、
665         * fileURL = "{&#064;USER.ID}" と指定すると、FILE_URL 属性で指定のフォルダの下に、
666         * さらに、各個人ID別のフォルダを作成して、そこにセーブします。
667         * (初期値:システム定数のFILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。
668         *
669         * @og.rev 3.5.4.3 (2004/01/05) 内部処理を、makeFileURL に移動。
670         * @og.rev 4.0.0.0 (2005/01/31) StringUtil.urlAppend メソッドの利用
671         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
672         *
673         * @param       url 保存先ディレクトリ名
674         * @see         org.opengion.hayabusa.common.SystemData#FILE_URL
675         */
676        public void setFileURL( final String url ) {
677                String furl = nval( getRequestParameter( url ),null );
678                if( furl != null ) {
679                        char ch = furl.charAt( furl.length()-1 );
680                        if( ch != '/' && ch != '\\' ) { furl = furl + "/"; }
681                        fileURL = StringUtil.urlAppend( fileURL,furl );
682                }
683        }
684
685        /**
686         * 【TAG】ファイルを作成するときのファイル名をセットします(初期値:システムパラメータのFILE_FILENAME)。
687         *
688         * @og.tag ファイルを作成するときのファイル名をセットします。
689         *
690         * @param   fname ファイル名
691         */
692        public void setFilename( final String fname ) {
693                filename = nval( getRequestParameter( fname ),filename );
694        }
695
696        /**
697         * 【TAG】ZIPファイルを作成するときのZIPファイル名をセットします(初期値:filename + ".zip")。
698         *
699         * @og.tag
700         * zip 属性に、true を指定した場合に、ZIPファイル化します。その場合のファイル名を指定します。
701         * なにも指定しない場合は、filename + ".zip" になります。
702         *
703         * @param   zipFile ZIPファイル名
704         * @see #setZip( String )
705         */
706        public void setZipFilename( final String zipFile ) {
707                zipFilename = nval( getRequestParameter( zipFile ),zipFilename );
708        }
709
710        /**
711         * 【TAG】ファイルを作成するときのファイルエンコーディング名をセットします
712         *              (初期値:FILE_ENCODE[={@og.value org.opengion.hayabusa.common.SystemData#FILE_ENCODE}])。
713         *
714         * @og.tag
715         * "DEFAULT","JISAutoDetect" ,"JIS", "EUC_JP", "MS932", "SJIS" , "Windows-31J" , "Shift_JIS"
716         * (初期値:システム定数のFILE_ENCODE[={@og.value org.opengion.hayabusa.common.SystemData#FILE_ENCODE}])。
717         *
718         * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応 エンコードの取得方法変更
719         * @og.rev 3.1.3.0 (2003/04/10) FILE_ENCODE から、エンコード情報を取得する。
720         *
721         * @param   enc ファイルエンコーディング名
722         * @see     <a href="http://www.iana.org/assignments/character-sets">IANA Charset Registry</a>
723         * @see         org.opengion.hayabusa.common.SystemData#FILE_ENCODE
724         */
725        public void setEncode( final String enc ) {
726                encode = nval( getRequestParameter( enc ),encode );
727        }
728
729        /**
730         * 【TAG】ヘッダーを書き込むかどうか[true/false]を指定します(初期値:true)。
731         *
732         * @og.tag
733         *  #Name ・・・・ ヘッダーの書き込みを指定します。
734         * 通常は、書き込み(true)にしておき、使用側でコメントと解釈するように
735         * 処理を行うべきです。コメントのため、append モードで途中に現れても
736         * 無視できます。また、エンジン標準でデータを取り込む場合に、データの配置が
737         * 変更されても取り込みプログラムはそのまま使用できます。
738         * 初期値は、true(書き込む)です。
739         *
740         * @param   flag ヘッダーを書き込むかどうか [true:書き込む/false:書き込まない]
741         */
742        public void setUseHeader( final String flag ) {
743                useHeader = nval( getRequestParameter( flag ),useHeader );
744        }
745
746        /**
747         * 【TAG】追加モードで書き込むかどうか[true/false]を指定します(初期値:false[通常モード])。
748         *
749         * @og.tag
750         * ファイルを書き込む場合、追加モードで書き込むかどうかをセットします。
751         * 新規モード(true)の場合、既存のファイルが存在し、かつ書き込み許可があれば、
752         * 上書きで新規に作成します。
753         * 初期値は、false(新規モード)です。
754         *
755         * @param   flag [true:追加モード/false:新規モード]
756         */
757        public void setFileAppend( final String flag ) {
758                fileAppend = nval( getRequestParameter( flag ),fileAppend );
759        }
760
761        /**
762         * 【TAG】結果をファイルに出力するときに、ZIPで圧縮するかどうか[true/false]を指定します(初期値:false)。
763         *
764         * @og.tag
765         * 大量に抜き出す場合、そのまま、サーバーから取り出すだけでも大変です。
766         * zip 属性を、true にすると、GZIP で圧縮したファイルを作成します。
767         * 初期値は、false(圧縮しない)です。
768         *
769         * @param  flag ZIPで圧縮 [true:する/それ以外:しない]
770         * @see    #setZipFilename( String )
771         */
772        public void setZip( final String flag ) {
773                zip = nval( getRequestParameter( flag ),zip );
774        }
775
776        /**
777         * 【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します(初期値:MSG0033[ 件検索しました])。
778         *
779         * @og.tag
780         * ここでは、検索結果の件数や登録された件数をまず出力し、
781         * その次に、ここで指定したメッセージをリソースから取得して
782         * 表示します。
783         * 表示させたくない場合は, displayMsg = "" をセットしてください。
784         * 初期値は、検索件数を表示します。
785         *
786         * @param       id ディスプレイに表示させるメッセージ ID
787         */
788        public void setDisplayMsg( final String id ) {
789                String ids = getRequestParameter( id );
790                if( ids != null ) { displayMsg = ids; }
791        }
792
793        /**
794         * 【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])。
795         *
796         * @og.tag
797         * ここでは、検索結果がゼロ件の場合のみ、特別なメッセージを表示させます。
798         * 従来は、displayMsg と兼用で、『0 件検索しました』という表示でしたが、
799         * displayMsg の初期表示は、OFF になりましたので、ゼロ件の場合のみ別に表示させます。
800         * 表示させたくない場合は, notfoundMsg = "" をセットしてください。
801         * 初期値は、MSG0077[対象データはありませんでした]です。
802         *
803         * @param       id ディスプレイに表示させるメッセージ ID
804         */
805        public void setNotfoundMsg( final String id ) {
806                String ids = getRequestParameter( id );
807                if( ids != null ) { notfoundMsg = ids; }
808        }
809
810        /**
811         * 【TAG】(通常は使いません)データのフェッチサイズを指定します(初期値:100)。
812         *
813         * @og.tag
814         * より多くの行が必要なときに、データベースから取り出す必要がある行数に
815         * ついてのヒントを JDBC ドライバに提供します。
816         * 指定された行数は、この Statement を使って作成された結果セットにだけ影響します。
817         * 指定された値が 0 の場合、ヒントは無視されます。
818         * 初期値は、100 です。
819         *
820         * @param       size フェッチする行数(初期値:100)
821         */
822        public void setFetchSize( final String size ) {
823                fetchSize = nval( getRequestParameter( size ),fetchSize );
824        }
825
826        /**
827         * 【TAG】PL/SQLを利用する場合の引数にセットすべき データの名称をCSV形式で複数指定します。
828         *
829         * @og.tag
830         * 複数ある場合は、カンマ区切り文字で渡します。
831         * PL/SQL を使用しない場合は、無視されます。
832         *
833         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
834         *
835         * @param       nm 引数の名称(複数ある場合は、カンマ区切り文字)
836         */
837        public void setNames( final String nm ) {
838                names = nval( getRequestParameter( nm ),names );
839        }
840
841        /**
842         * 【TAG】Query を発行する為のクラスID(JDBC,JDBCErrMsg)を指定します({@og.doc03Link queryType 初期値:JDBC})。
843         *
844         * @og.tag
845         * ストアドプロシージャ等を実行する場合に、queryType="JDBCErrMsg" を
846         * 指定する必要があります。(それ以外の指定は、初期値の JDBC になります。)
847         * 初期値は、"JDBC" です。
848         * {@og.doc03Link queryType Query_**** クラス}
849         *
850         * @og.rev 3.6.1.0 (2005/01/05) PL/SQLコール(JDBCErrMsg 形式)への対応
851         *
852         * @param       id Query を発行する為の実クラス ID
853         */
854        public void setQueryType( final String id ) {
855                // 内部的には、JDBCErrMsg:false / それ以外:true で管理しています。
856                queryType = ! "JDBCErrMsg".equalsIgnoreCase( getRequestParameter( id ) );
857        }
858
859        /**
860         * 【TAG】ファイルに行番号を出力するかどうか(初期値:true)
861         *
862         * @og.tag
863         * ファイルに行番号を出力するかどうかを指定します。
864         * 初期値は、true(出力する)です。
865         * 
866         * @og.rev 5.5.7.1 (2012/10/05) 新規追加
867         * @param  flag 行番号出力 [true:する/それ以外:しない]
868         */
869        public void setUseNumber( final String flag ) {
870                useNumber = nval( getRequestParameter( flag ),useNumber );
871        }
872        
873        /**
874         * シリアライズ用のカスタムシリアライズ書き込みメソッド
875         *
876         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
877         * @serialData 一部のオブジェクトは、シリアライズされません。
878         *
879         * @param strm ObjectOutputStreamオブジェクト
880         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
881         */
882        private void writeObject( final ObjectOutputStream strm ) throws IOException {
883                strm.defaultWriteObject();
884        }
885
886        /**
887         * シリアライズ用のカスタムシリアライズ読み込みメソッド
888         *
889         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
890         *
891         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
892         * @serialData 一部のオブジェクトは、シリアライズされません。
893         *
894         * @param strm ObjectInputStreamオブジェクト
895         * @see #release2()
896         */
897        private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
898                strm.defaultReadObject();
899        }
900
901        /**
902         * 【TAG】保存先ストレージタイプを設定します。
903         *  
904         * @og.tag
905         * ファイルを保存するストレージタイプを設定します。
906         * 未設定の場合は、システムリソースの「CLOUD_TARGET」が参照されます。
907         * 自身のサーバを指定する場合は、「default」を設定してください。
908         * 
909         * @og.rev 5.10.9.0 (2019/03/01) 新規追加
910         * 
911         * @param storage ストレージタイプ
912         */
913        public void setStorageType( final String storage ) {
914                storageType = nval( getRequestParameter( storage ), storageType );
915        }
916        
917        /**
918         * 【TAG】保存先バケット名を設定します。
919         * 
920         * @og.tag
921         * ファイルを保存するバケット名を指定します。
922         * クラウドストレージ利用時のみ有効です。
923         * 未設定の場合は、システムリソースの「CLOUD_BUKET」が参照されます。
924         * 
925         * @og.rev 5.10.9.0 (2019/03/01) 新規追加
926         * 
927         * @param bucket バケット名
928         */
929        public void setBucketName( final String bucket ) {
930                bucketName = nval( getRequestParameter( bucket ), bucketName );
931        }
932        
933        /**
934         * このオブジェクトの文字列表現を返します。
935         * 基本的にデバッグ目的に使用します。
936         *
937         * @og.rev 5.10.9.0 (2019/03/01) storageType,bucketNameを出力対象に追加。
938         *
939         * @return このクラスの文字列表現
940         */
941        @Override
942        public String toString() {
943                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
944                                .println( "VERSION"             ,VERSION        )
945                                .println( "dbid"                ,dbid           )
946                                .println( "separator"   ,separator      )
947                                .println( "useHeader"   ,useHeader      )
948                                .println( "fileURL"             ,fileURL        )
949                                .println( "filename"    ,filename       )
950                                .println( "zipFilename" ,zipFilename)
951                                .println( "sql"                 ,sql            )
952                                .println( "encode"              ,encode         )
953                                .println( "fileAppend"  ,fileAppend     )
954                                .println( "zip"                 ,zip            )
955                                .println( "displayMsg"  ,displayMsg     )
956                                .println( "dyStart"             ,dyStart        )
957                                .println( "fetchSize"   ,fetchSize      )
958                                .println( "queryType"   ,queryType      )
959                                .println( "names"               ,names          )
960                                .println( "errCode"             ,errCode        )
961                                .println( "storageType" ,storageType )
962                                .println( "bucketName"  ,bucketName     )
963                                .println( "Other..."    ,getAttributes().getAttribute() )
964                                .fixForm().toString() ;
965        }
966}