    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.db;
    017
    018import java.io.IOException;
    019import java.io.Reader;
    020import java.sql.CallableStatement;
    021import java.sql.Clob;
    022import java.sql.Connection;
    023import java.sql.PreparedStatement;
    024import java.sql.ParameterMetaData;
    025import java.sql.ResultSet;
    026import java.sql.ResultSetMetaData;
    027import java.sql.SQLException;
    028import java.sql.Types;
    029import java.util.ArrayList;
    030import java.util.Locale;
    031
    032// import java.text.DateFormat;                         // 5.5.5.4 (2012/08/18) DATE,TIMESTAMP の処理を利用時にコメントを外す
    033// import java.text.SimpleDateFormat;           // 5.5.5.4 (2012/08/18) DATE,TIMESTAMP の処理を利用時にコメントを外す
    034
    035import org.opengion.fukurou.util.ApplicationInfo;
    036import org.opengion.fukurou.util.Closer;
    037import org.opengion.fukurou.util.StringUtil;
    038import org.opengion.fukurou.util.HybsDateUtil;
    039
    040/**
    041 * データベース関連の便利なメソッドを集めた簡易ユーティリティークラスです。
    042 * 全てのメソッドは、static メソッドになっています。
    043 *
    044 * @og.rev 2.1.1.1 (2002/11/15) Serializable インターフェースを削除する。
    045 * @og.rev 4.0.0.0 (2007/10/16) DBアクセス関係のメソッドのみをパッケージ移動(hayabusa/db ⇒ fukurou/db)
    046 * @og.group ＤＢ/Shell制御
    047 *
    048 * @version  4.0
    049 * @author   Kazuhiko Hasegawa
    050 * @since    JDK5.0,
    051 */
    052public final class DBUtil {
    053
    054        /** システム依存の改行記号をセットします。4.0.0.0(2007/10/17) */
    055        private static final String CR = System.getProperty( "line.separator" );
    056
    057        /**
    058         * インスタンスを作らないので、コンストラクタは、private に設定します。
    059         */
    060        private DBUtil() {}
    061
    062        /**
    063         * 初期データベースに接続して、Queryを実行します(互換性確保のため残しています)。
    064         *
    065         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
    066         * 結果は,すべて文字列に変換されて格納されます。
    067         *
    068         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    069         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
    070         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    071         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
    072         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    073         *
    074         * @param   stmt ステートメント文字列
    075         * @param   args オブジェクトの引数配列
    076         * @param   appInfo アプリ情報オブジェクト
    077         *
    078         * @return  検索結果の配列
    079         */
    080        public static String[][] dbExecute( final String stmt ,final String[] args ,final ApplicationInfo appInfo ) {
    081//              return dbExecute( stmt ,args,appInfo,"DEFAULT" );
    082//              return dbExecute( stmt, args, appInfo, null );
    083
    084//              Transaction tran = new TransactionReal( null,appInfo );
    085                Transaction tran = new TransactionReal( appInfo );                      // 5.3.7.0 (2011/07/01) 引数変更
    086//              return dbExecute( stmt, args, tran, null, false );
    087
    088                // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    089                try {
    090                        return dbExecute( stmt, args, tran, null, false );
    091                }
    092                finally {
    093                        // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。
    094                        tran.close();
    095                }
    096        }
    097
    098        /**
    099         * 初期データベースに接続して、Queryを実行します(Transaction 対応)。
    100         *
    101         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
    102         * 結果は,すべて文字列に変換されて格納されます。
    103         * ここでは、Transactionオブジェクトから、Connection を取り出して使用します。
    104         *
    105         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
    106         *
    107         * @param   stmt ステートメント文字列
    108         * @param   args オブジェクトの引数配列
    109         * @param   tran Transactionオブジェクト
    110         *
    111         * @return  検索結果の配列
    112         */
    113        public static String[][] dbExecute( final String stmt ,final String[] args ,final Transaction tran ) {
    114                return dbExecute( stmt, args, tran, null, false );
    115        }
    116
    117        /**
    118         * 検索するデータベースを指定して、Queryを実行します(互換性確保のため残しています)。
    119         *
    120         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
    121         * 結果は,すべて文字列に変換されて格納されます。
    122         * 追加：検索以外のSQLも実行できます。結果は、null を返します。
    123         *
    124         * @og.rev 3.0.0.0 (2002/12/25) 検索のみのクエリーから、何でもありのクエリーに変更
    125         * @og.rev 2.3.1.3 (2003/01/28) Open Cursor が、大量に残る件の対応。ResultSet を close()
    126         * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ＋Queryに変更します。
    127         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    128         * @og.rev 4.0.0.1 (2007/12/03) try 〜 catch 〜 finally をきちんと行う。
    129         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    130         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
    131         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    132         *
    133         * @param   stmt ステートメント文字列
    134         * @param   args オブジェクトの引数配列
    135         * @param   appInfo アプリ情報オブジェクト
    136         * @param   dbid 接続先ID
    137         *
    138         * @return  検索結果の配列
    139         */
    140        public static String[][] dbExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo, final String dbid ) {
    141//              return dbExecute( stmt, args, appInfo, dbid, false );
    142
    143//              Transaction tran = new TransactionReal( dbid,appInfo );
    144                Transaction tran = new TransactionReal( appInfo );                      // 5.3.7.0 (2011/07/01) 引数変更
    145//              return dbExecute( stmt, args, tran, dbid, false  );
    146
    147                // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    148                try {
    149                        return dbExecute( stmt, args, tran, dbid, false  );
    150                }
    151                finally {
    152                        // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。
    153                        tran.close();
    154                }
    155        }
    156
    157        /**
    158         * 検索するデータベースを指定して、Queryを実行します(Transaction 対応)。
    159         *
    160         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
    161         * 結果は,すべて文字列に変換されて格納されます。
    162         * 追加：検索以外のSQLも実行できます。結果は、null を返します。
    163         * ここでは、Transactionオブジェクトから、Connection を取り出して使用します。
    164         *
    165         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
    166         *
    167         * @param   stmt ステートメント文字列
    168         * @param   args オブジェクトの引数配列
    169         * @param   tran Transactionオブジェクト
    170         * @param   dbid 接続先ID
    171         *
    172         * @return  検索結果の配列
    173         */
    174        public static String[][] dbExecute( final String stmt ,final String[] args, final Transaction tran , final String dbid ) {
    175                return dbExecute( stmt, args, tran, dbid, false );
    176        }
    177
    178        /**
    179         * 検索するデータベースを指定して、Queryを実行します(互換性確保のため残しています)。
    180         *
    181         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
    182         * 結果は,すべて文字列に変換されて格納されます。
    183         * 追加：検索以外のSQLも実行できます。結果は、null を返します。
    184         *
    185         * @og.rev 4.3.7.0 (2009/06/01) 新規作成
    186         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    187         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    188         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
    189         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    190         *
    191         * @param   stmt ステートメント文字列
    192         * @param   args オブジェクトの引数配列
    193         * @param   appInfo アプリ情報オブジェクト
    194         * @param   dbid 接続先ID
    195         * @param   useHeader 1行目にヘッダーを含めるか
    196         *
    197         * @return  検索結果の配列
    198         */
    199        public static String[][] dbExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo, final String dbid, final boolean useHeader ) {
    200//              Transaction tran = new TransactionReal( dbid,appInfo );
    201                Transaction tran = new TransactionReal( appInfo );                      // 5.3.7.0 (2011/07/01) 引数変更
    202//              return dbExecute( stmt, args, tran, dbid, useHeader );
    203
    204                // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    205                try {
    206                        return dbExecute( stmt, args, tran, dbid, useHeader );
    207                }
    208                finally {
    209                        // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。
    210                        tran.close();
    211                }
    212        }
    213
    214        /**
    215         * 検索するデータベースを指定して、Queryを実行します(Transaction 対応)。
    216         *
    217         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
    218         * 結果は,すべて文字列に変換されて格納されます。
    219         * 追加：検索以外のSQLも実行できます。結果は、null を返します。
    220         *
    221         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
    222         * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
    223         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応
    224         *
    225         * @param   stmt ステートメント文字列
    226         * @param   args オブジェクトの引数配列
    227         * @param   tran Transactionオブジェクト
    228         * @param   dbid 接続先ID
    229         * @param   useHeader 1行目にヘッダーを含めるか
    230         *
    231         * @return  検索結果の配列
    232         */
    233//      public static String[][] dbExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo, final String dbid, final boolean useHeader ) {
    234        public static String[][] dbExecute( final String stmt ,final String[] args, final Transaction tran, final String dbid, final boolean useHeader ) {
    235//              Connection conn = null;                         // 5.1.9.0 (2010/08/01) Transaction 対応
    236                PreparedStatement pstmt = null;
    237                ResultSet resultSet = null;
    238                String[][] rtn = null;
    239//              boolean errFlag = true;
    240                try {
    241//                      conn = ConnectionFactory.connection( dbid,appInfo );
    242                        Connection conn = tran.getConnection( dbid );                           // 5.1.9.0 (2010/08/01) Transaction 対応
    243                        pstmt = conn.prepareStatement( stmt );
    244                        if( args != null ) {
    245                                // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    246//                              boolean useParamMetaData = ApplicationInfo.useParameterMetaData( conn );
    247                                boolean useParamMetaData = ConnectionFactory.useParameterMetaData( dbid );      // 5.3.8.0 (2011/08/01)
    248                                if( useParamMetaData ) {
    249                                        ParameterMetaData pMeta = pstmt.getParameterMetaData();
    250                                        for( int i=0; i<args.length; i++ ) {
    251                                                int type = pMeta.getParameterType( i+1 );
    252                                                // 5.3.8.0 (2011/08/01) setNull 対応
    253//                                              pstmt.setObject( i+1,args[i],type );
    254                                                String val = args[i];
    255                                                if( val == null || val.isEmpty() ) {
    256                                                        pstmt.setNull( i+1, type );
    257                                                }
    258                                                else {
    259                                                        pstmt.setObject( i+1, val, type );
    260                                                }
    261                                        }
    262                                }
    263                                else {
    264                                        for( int i=0; i<args.length; i++ ) {
    265                                                pstmt.setObject( i+1,args[i] );
    266                                        }
    267                                }
    268                        }
    269                        boolean status = pstmt.execute();
    270                        if( status ) {
    271                                resultSet = pstmt.getResultSet();
    272//                              rtn = DBUtil.resultToArray( resultSet,false );
    273                                rtn = DBUtil.resultToArray( resultSet,useHeader ); // 4.3.7.0 (2009/06/01)
    274                        }
    275                        else {
    276//                              conn.commit();
    277                                tran.commit();                  // 5.1.9.0 (2010/08/01) Transaction 対応
    278                        }
    279//                      errFlag = false;        // エラーでない
    280                }
    281                catch ( SQLException ex ) {
    282//                      Closer.rollback( conn );
    283                        tran.rollback();                        // 5.1.9.0 (2010/08/01) Transaction 対応
    284                        String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR
    285                                                + "SQL=[" + stmt + "]" + CR
    286                                                + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR
    287                                                + "DBID=[" + dbid + "]" + CR;
    288                        throw new RuntimeException( errMsg,ex );
    289                }
    290                finally {
    291                        Closer.resultClose( resultSet );
    292                        Closer.stmtClose( pstmt );
    293
    294//                      if( errFlag ) { ConnectionFactory.remove( conn,dbid ); }
    295//                      else {                  ConnectionFactory.close( conn,dbid );  }
    296                        // 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
    297//                      tran.close( errFlag );          // 5.1.9.0 (2010/08/01) Transaction 対応
    298                }
    299                return rtn;
    300        }
    301
    302        /**
    303         * 初期データベースに接続して、CallableStatement(PL/SQL)を実行します(互換性確保のため残しています)。
    304         * ステートメントと引数により、CallableStatement クエリーを実行します。
    305         * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に
    306         * 設定して返します。
    307         * ステートメント文字列には、 { call PLSQL( ?,?,?･･･ ) } となります。
    308         * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。
    309         * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。
    310         *
    311         * @og.rev 3.8.0.0 (2005/06/07) 新規追加
    312         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    313         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
    314         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    315         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
    316         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    317         *
    318         * @param   stmt ステートメント文字列
    319         * @param   args オブジェクトの引数配列
    320         * @param   appInfo アプリ情報オブジェクト
    321         *
    322         * @return  実行結果([0]=ステータス、[1]=エラーメッセージ
    323         */
    324        public static String[] dbCallExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo ) {
    325//              return dbCallExecute( stmt ,args,appInfo,"DEFAULT" );
    326//              return dbCallExecute( stmt ,args, appInfo, null );
    327
    328//              Transaction tran = new TransactionReal( null,appInfo );
    329                Transaction tran = new TransactionReal( appInfo );                      // 5.3.7.0 (2011/07/01) 引数変更
    330//              return dbCallExecute( stmt ,args, tran, null );
    331
    332                // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    333                try {
    334                        return dbCallExecute( stmt ,args, tran, null );
    335                }
    336                finally {
    337                        // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。
    338                        tran.close();
    339                }
    340        }
    341
    342        /**
    343         * 初期データベースに接続して、CallableStatement(PL/SQL)を実行します(Transaction 対応)。
    344         * ステートメントと引数により、CallableStatement クエリーを実行します。
    345         * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に
    346         * 設定して返します。
    347         * ステートメント文字列には、 { call PLSQL( ?,?,?･･･ ) } となります。
    348         * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。
    349         * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。
    350         *
    351         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
    352         *
    353         * @param   stmt ステートメント文字列
    354         * @param   args オブジェクトの引数配列
    355         * @param   tran Transactionオブジェクト
    356         *
    357         * @return  実行結果([0]=ステータス、[1]=エラーメッセージ
    358         */
    359        public static String[] dbCallExecute( final String stmt ,final String[] args, final Transaction tran ) {
    360                return dbCallExecute( stmt ,args, tran, null );
    361        }
    362
    363        /**
    364         * 検索するデータベースを指定して、CallableStatement(PL/SQL)を実行します(互換性確保のため残しています)。
    365         * ステートメントと引数により、CallableStatement クエリーを実行します。
    366         * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に
    367         * 設定して返します。
    368         * ステートメント文字列には、 { call PLSQL( ?,?,?･･･ ) } となります。
    369         * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。
    370         * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。
    371         * 検索するデータベースは、DEFAULT です。
    372         *
    373         * @og.rev 3.8.0.0 (2005/06/07) 新規追加
    374         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    375         * @og.rev 4.0.0.1 (2007/12/03) try 〜 catch 〜 finally をきちんと行う。
    376         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    377         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
    378         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    379         *
    380         * @param   stmt ステートメント文字列
    381         * @param   args オブジェクトの引数配列
    382         * @param   appInfo アプリ情報オブジェクト
    383         * @param   dbid 接続先ID
    384         *
    385         * @return  実行結果([0]=ステータス、[1]=エラーメッセージ
    386         */
    387        public static String[] dbCallExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo ,final String dbid ) {
    388//              Transaction tran = new TransactionReal( dbid,appInfo );
    389                Transaction tran = new TransactionReal( appInfo );                      // 5.3.7.0 (2011/07/01) 引数変更
    390//              return dbCallExecute( stmt ,args, tran, dbid );
    391
    392                // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    393                try {
    394                        return dbCallExecute( stmt ,args, tran, dbid );
    395                }
    396                finally {
    397                        // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。
    398                        tran.close();
    399                }
    400        }
    401
    402        /**
    403         * 検索するデータベースを指定して、CallableStatement(PL/SQL)を実行します(Transaction 対応)。
    404         * ステートメントと引数により、CallableStatement クエリーを実行します。
    405         * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に
    406         * 設定して返します。
    407         * ステートメント文字列には、 { call PLSQL( ?,?,?･･･ ) } となります。
    408         * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。
    409         * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。
    410         * 検索するデータベースは、DEFAULT です。
    411         *
    412         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
    413         * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
    414         *
    415         * @param   stmt ステートメント文字列
    416         * @param   args オブジェクトの引数配列
    417         * @param   tran Transactionオブジェクト
    418         * @param   dbid 接続先ID
    419         *
    420         * @return  実行結果([0]=ステータス、[1]=エラーメッセージ
    421         */
    422        public static String[] dbCallExecute( final String stmt ,final String[] args, final Transaction tran ,final String dbid ) {
    423//              Connection conn = null ;                                // 5.1.9.0 (2010/08/01) Transaction 対応
    424                CallableStatement callStmt = null ;
    425
    426                String[] rtn = new String[2] ;
    427
    428//              boolean errFlag = true;
    429                try {
    430//                      conn = ConnectionFactory.connection( dbid,appInfo );
    431                        Connection conn = tran.getConnection( dbid );                           // 5.1.9.0 (2010/08/01) Transaction 対応
    432                        callStmt = conn.prepareCall( stmt );
    433
    434                        callStmt.registerOutParameter( 1, Types.INTEGER );
    435                        callStmt.registerOutParameter( 2, Types.VARCHAR );
    436                        if( args != null ) {
    437                                for( int i=0; i<args.length; i++ ) {
    438                                        callStmt.setObject( i+3,args[i] );
    439                                }
    440                        }
    441                        callStmt.execute();
    442
    443                        rtn[0] = String.valueOf( callStmt.getInt(1) );  // 結果ステータス
    444                        rtn[1] = callStmt.getString(2);                                 // 内容(エラーメッセージ)
    445
    446//                      conn.commit();
    447                        tran.commit();                                  // 5.1.9.0 (2010/08/01) Transaction 対応
    448//                      errFlag = false;        // エラーでない
    449                }
    450                catch ( SQLException ex ) {
    451//                      Closer.rollback( conn );
    452                        tran.rollback();                                // 5.1.9.0 (2010/08/01) Transaction 対応
    453                        String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR
    454                                                + "SQL=[" + stmt + "]" + CR
    455                                                + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR
    456                                                + "DBID=[" + dbid + "]" + CR;
    457                        throw new RuntimeException( errMsg,ex );
    458                }
    459                finally {
    460                        Closer.stmtClose( callStmt );
    461//                      if( errFlag ) { ConnectionFactory.remove( conn,dbid ); }
    462//                      else {                  ConnectionFactory.close( conn,dbid );  }
    463                        // 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
    464//                      tran.close( errFlag );          // 5.1.9.0 (2010/08/01) Transaction 対応
    465                }
    466                return rtn;
    467        }
    468
    469        /**
    470         * SQL文の実行結果において、データの件数を取得します(互換性確保のため残しています)。
    471         * ステートメントと引数により、Prepared クエリーの検索を実行します。
    472         * 結果は、件数を数値で返します。
    473         * あくまで、存在チェックに必要な処理のみ行っているため、通常の検索より高速です。
    474         *
    475         * @og.rev 3.5.0.0 (2003/09/17) 新規作成
    476         * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ＋Queryに変更します。
    477         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    478         * @og.rev 4.0.0.1 (2007/12/03) try 〜 catch 〜 finally をきちんと行う。
    479         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    480         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    481         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
    482         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    483         *
    484         * @param   stmt ステートメント文字列
    485         * @param   args オブジェクトの引数配列
    486         * @param   appInfo アプリ情報オブジェクト
    487         * @param   dbid 接続先ID
    488         *
    489         * @return  検索結果(データの件数)
    490         */
    491        public static int dbExist( final String stmt ,final String[] args, final ApplicationInfo appInfo , final String dbid ) {
    492//              Transaction tran = new TransactionReal( dbid,appInfo );
    493                Transaction tran = new TransactionReal( appInfo );                      // 5.3.7.0 (2011/07/01) 引数変更
    494//              return dbExist( stmt ,args, tran , dbid );
    495
    496                // 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
    497                try {
    498                        return dbExist( stmt ,args, tran , dbid );
    499                }
    500                finally {
    501                        // エラー発生時は、tran.rollback() が呼ばれているため、close()時にエラーフラグをセットする必要はない。
    502                        tran.close();
    503                }
    504        }
    505
    506        /**
    507         * SQL文の実行結果において、データの件数を取得します(Transaction 対応)。
    508         * ステートメントと引数により、Prepared クエリーの検索を実行します。
    509         * 結果は、件数を数値で返します。
    510         * あくまで、存在チェックに必要な処理のみ行っているため、通常の検索より高速です。
    511         *
    512         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
    513         * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
    514         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応
    515         *
    516         * @param   stmt ステートメント文字列
    517         * @param   args オブジェクトの引数配列
    518         * @param   tran Transactionオブジェクト
    519         * @param   dbid 接続先ID
    520         *
    521         * @return  検索結果(データの件数)
    522         */
    523        public static int dbExist( final String stmt ,final String[] args, final Transaction tran , final String dbid ) {
    524//              Connection conn = null;                         // 5.1.9.0 (2010/08/01) Transaction 対応
    525                PreparedStatement pstmt = null;
    526                ResultSet resultSet = null;
    527                int rtnCnt = -1;
    528
    529//              boolean errFlag = true;
    530                try {
    531//                      conn = ConnectionFactory.connection( dbid,appInfo );
    532                        Connection conn = tran.getConnection( dbid );                           // 5.1.9.0 (2010/08/01) Transaction 対応
    533                        pstmt = conn.prepareStatement( stmt );
    534                        if( args != null ) {
    535                                // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    536//                              boolean useParamMetaData = ApplicationInfo.useParameterMetaData( conn );
    537                                boolean useParamMetaData = ConnectionFactory.useParameterMetaData( dbid );      // 5.3.8.0 (2011/08/01)
    538                                if( useParamMetaData ) {
    539                                        ParameterMetaData pMeta = pstmt.getParameterMetaData();
    540                                        for( int i=0; i<args.length; i++ ) {
    541                                                int type = pMeta.getParameterType( i+1 );
    542                                                // 5.3.8.0 (2011/08/01) setNull 対応
    543//                                              pstmt.setObject( i+1,args[i],type );
    544                                                String val = args[i];
    545                                                if( val == null || val.isEmpty() ) {
    546                                                        pstmt.setNull( i+1, type );
    547                                                }
    548                                                else {
    549                                                        pstmt.setObject( i+1, val, type );
    550                                                }
    551                                        }
    552                                }
    553                                else {
    554                                        for( int i=0; i<args.length; i++ ) {
    555                                                pstmt.setObject( i+1,args[i] );
    556                                        }
    557                                }
    558                        }
    559
    560                        resultSet = pstmt.executeQuery();
    561                        if( resultSet.next() ) {
    562                                rtnCnt = resultSet.getInt(1);
    563                        }
    564//                      errFlag = false;        // エラーでない
    565                }
    566                catch ( SQLException ex ) {
    567                        String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR
    568                                                + "SQL=[" + stmt + "]" + CR
    569                                                + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR
    570                                                + "DBID=[" + dbid + "]" + CR;
    571                        throw new RuntimeException( errMsg,ex );                // 3.5.5.4 (2004/04/15) 引数の並び順変更
    572                }
    573                finally {
    574                        Closer.resultClose( resultSet );
    575                        Closer.stmtClose( pstmt );
    576
    577//                      if( errFlag ) { ConnectionFactory.remove( conn,dbid ); }
    578//                      else {                  ConnectionFactory.close( conn,dbid );  }
    579                        // 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
    580//                      tran.close( errFlag );          // 5.1.9.0 (2010/08/01) Transaction 対応
    581                }
    582                return rtnCnt;
    583        }
    584
    585        /**
    586         * ResultSet より、結果の文字列配列を作成します。
    587         *
    588         * 結果は,すべて文字列に変換されて格納されます。
    589         * 移動したメソッドで使われているのでこれも移動
    590         *
    591         * @og.rev 3.1.0.0 (2003/03/20) Vector を使用している箇所で、非同期でも構わない箇所を、ArrayList に置換え。
    592         * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ＋Queryに変更します。
    593         * @og.rev 4.0.0.0 (2005/01/31) private ⇒ public , ヘッダー情報の取得有無フラグの追加
    594         * @og.rev 5.6.7.0 (2013/07/27) CLOB 対応
    595         *
    596         * @param   resultSet ResultSetオブジェクト
    597         * @param   useHeader true:ヘッダーを第一行に含める/false:含めない
    598         *
    599         * @return  ResultSetの検索結果配列
    600         */
    601        public static String[][] resultToArray( final ResultSet resultSet,final boolean useHeader ) {
    602                ArrayList<String[]> data = new ArrayList<String[]>();
    603                try {
    604                        ResultSetMetaData metaData  = resultSet.getMetaData();
    605                        int numberOfColumns =  metaData.getColumnCount();
    606
    607                        String[] columnNames = new String[numberOfColumns];
    608                        // 5.6.7.0 (2013/07/27) CLOB 対応
    609                        int[] type = new int[numberOfColumns];
    610                        boolean useClob = false;                                                                                // そもそも、CLOB系のカラムがあるかどうか
    611                        for( int i = 0; i < numberOfColumns; i++ ) {
    612                                int tp = metaData.getColumnType( i+1 );
    613                                type[i] = tp ;
    614                                if( tp == Types.CLOB || tp == Types.ROWID || tp == Types.TIMESTAMP ) { useClob = true; }
    615                                if( useHeader ) {
    616                                        columnNames[i] = ( metaData.getColumnLabel(i+1) ).toUpperCase(Locale.JAPAN) ;
    617                                }
    618                        }
    619
    620                        if( useHeader ) { data.add( columnNames ); }
    621
    622                        // 5.6.7.0 (2013/07/27) CLOB 対応 で、ヘッダーループを回すので、処理方法を変更
    623//                      if( useHeader ) {
    624//                              String[] columnNames = new String[numberOfColumns];
    625//                              for( int column = 0; column < numberOfColumns; column++ ) {
    626//                                      columnNames[column]      = ( metaData.getColumnLabel(column+1) ).toUpperCase(Locale.JAPAN) ;
    627//                              }
    628//                              data.add( columnNames );
    629//                      }
    630
    631                        // 5.6.7.0 (2013/07/27) CLOB 対応。ついでに、ループカウンタを、0からに変更します。
    632                        while( resultSet.next() ) {
    633                                String[] columnValues = new String[numberOfColumns];
    634                                for( int i = 0; i < numberOfColumns; i++ ) {
    635                                        Object obj = resultSet.getObject(i+1);
    636                                        if( obj == null ) {
    637                                                columnValues[i] = "";
    638                                        }
    639                                        else if( useClob ) {
    640                                                columnValues[i] = getValue( resultSet, i ,type[i] );
    641                                        }
    642                                        else {
    643                                                columnValues[i] = String.valueOf( obj );
    644                                        }
    645                                }
    646                                data.add( columnValues );
    647                        }
    648
    649//                      while( resultSet.next() ) {
    650//                              String[] columnValues = new String[numberOfColumns];
    651//                              for( int i = 1; i <= numberOfColumns; i++ ) {
    652//                                      Object obj = resultSet.getObject(i);
    653//                                      if( obj == null ) {
    654//                                              columnValues[i-1] = "";
    655//                                      }
    656//                                      else {
    657//                                              columnValues[i-1] = String.valueOf( obj );
    658//                                      }
    659//                              }
    660//                              data.add( columnValues );
    661//                      }
    662                }
    663                catch ( SQLException ex ) {
    664                        String errMsg = "処理結果を実行できませんでした。"
    665                                                + CR + ex.getMessage() ;
    666                        throw new RuntimeException( errMsg,ex );                // 3.5.5.4 (2004/04/15) 引数の並び順変更
    667                }
    668
    669                int size = data.size();
    670                String[][] rtn = new String[size][];
    671                for( int i=0; i<size; i++ ) {
    672                        rtn[i] = data.get(i);
    673                }
    674
    675                return rtn;
    676        }
    677
    678        /**
    679         * 検索結果オブジェクトから値を取り出します。
    680         *
    681         * @og.rev 5.3.6.0 (2011/06/01) 集計機能対応によりメソッド化
    682         * @og.rev 5.5.5.4 (2012/08/18) if文をcase文に置き換え。
    683         * @og.rev 5.5.5.4 (2012/08/18) TIMESTAMP の処理を追加。
    684         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
    685         *
    686         * @param res 検索結果オブジェクト
    687         * @param col カラム(0から始まる値。このメソッドの内部で、＋１しています)
    688         * @param type データタイプ(java.sql.Types.XXXX)
    689         *
    690         * @return 値
    691         * @throws SQLException データベースアクセスエラー
    692         */
    693        public static String getValue( final ResultSet res, final int col, final int type ) throws SQLException {
    694                String val = null;
    695
    696                Object obj = res.getObject(col+1);
    697                if( obj == null ) {
    698                        val = "";
    699                }
    700                else {
    701                        switch( type ) {
    702                                case Types.CLOB :               val = getClobData( (Clob)obj ) ;        break;
    703                                case Types.ROWID:               val = res.getString(col+1);                     break;
    704//                              case Types.TIMESTAMP :  val = DATE_FMT.format( (java.sql.Timestamp)obj );       break;
    705                                case Types.TIMESTAMP :  val = HybsDateUtil.getDate( ((java.sql.Timestamp)obj).getTime() , "yyyyMMddHHmmss" );   break;
    706                                default :                               val = String.valueOf( obj );
    707                        }
    708                }
    709
    710                return val;
    711
    712//              5.5.5.4 (2012/08/18) if文をcase文に置き換え
    713//              if( type == Types.CLOB ) {
    714//                      Object obj = res.getObject(col+1);
    715//                      val = getClobData( (Clob)obj ) ;
    716//              }
    717//              else if( type == Types.ROWID ) {
    718//                      String obj = res.getString(col+1);
    719//                      if( obj == null ) {
    720//                              val = "";
    721//                      }
    722//                      else {
    723//                              val = obj;
    724//                      }
    725//              }
    726//              else {
    727//                      Object obj = res.getObject(col+1);
    728//                      if( obj == null ) {
    729//                              val = "";
    730//                      }
    731//                      else {
    732//                              val = String.valueOf( obj );
    733//                      }
    734//              }
    735//
    736//              return val;
    737        }
    738
    739        // 5.5.5.4 (2012/08/18) DATE,TIMESTAMP の処理を追加
    740//              private static final DateFormat DATE_FMT = new SimpleDateFormat( "yyyyMMddHHmmss",Locale.JAPAN );
    741
    742        /**
    743         * コネクションオブジェクトからデータベースのProductNameを取り出します。
    744         * ProductName は、小文字化して返します。
    745         * また、処理エラーが発生した場合は、"none" を返します。
    746         * ここでは、SQLException は、発生させません。
    747         *
    748         * @og.rev 5.6.7.0 (2013/07/27) 新規追加
    749         * @og.rev 5.6.7.4 (2013/08/30) ProductNameの小文字化対応
    750         *
    751         * @param conn コネクションオブジェクト
    752         *
    753         * @return データベースのProductName
    754         */
    755        public static String getProductName( final Connection conn ) {
    756                String dbName ;
    757                try {
    758//                      dbName = conn.getMetaData().getDatabaseProductName();
    759                        dbName = conn.getMetaData().getDatabaseProductName().toLowerCase( Locale.JAPAN );       // 5.6.7.4 (2013/08/30)
    760                }
    761                catch( SQLException ex ) {
    762                        dbName = "none";
    763                }
    764                return dbName ;
    765        }
    766
    767        /**
    768         * Clob オブジェクトから文字列を取り出します。
    769         *
    770         * @og.rev 5.3.6.0 (2011/06/01) 新規作成
    771         *
    772         * @param       clobData Clobオブジェクト
    773         *
    774         * @return      Clobオブジェクトから取り出した文字列
    775         * @throws      SQLException データベースアクセスエラー
    776         */
    777        private static String getClobData( final Clob clobData ) throws SQLException {
    778                if( clobData == null ) { return ""; }
    779
    780                Reader reader = null;
    781                StringBuilder buf = new StringBuilder( 10000 );
    782
    783                try {
    784                        reader = clobData.getCharacterStream();
    785                        char[] ch = new char[10000];
    786                        int  len ;
    787                        while( (len = reader.read( ch )) >= 0 ) {
    788                                buf.append( ch,0,len );
    789                        }
    790                }
    791                catch( IOException ex ) {
    792                        String errMsg = "CLOBデータの読み込みに失敗しました。";
    793//                      throw new HybsSystemException( errMsg,ex );
    794                        throw new RuntimeException( errMsg,ex );
    795                }
    796                finally {
    797                        Closer.ioClose( reader );
    798                }
    799                return buf.toString();
    800        }
    801}