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.sql.CallableStatement;
019import java.sql.Connection;
020import java.sql.PreparedStatement;
021import java.sql.ParameterMetaData;
022import java.sql.ResultSet;
023import java.sql.SQLException;
024import java.sql.Types;
025import java.util.ArrayList;
026import java.util.Locale;
027
028import org.opengion.fukurou.system.OgRuntimeException ;                 // 6.4.2.0 (2016/01/29)
029import org.opengion.fukurou.util.StringUtil;
030import static org.opengion.fukurou.system.HybsConst.CR;                 // 6.1.0.0 (2014/12/26) refactoring
031
032/**
033 * データベース関連の便利なメソッドを集めた簡易ユーティリティークラスです。
034 * 全てのメソッドは、static メソッドになっています。
035 *
036 * @og.rev 2.1.1.1 (2002/11/15) Serializable インターフェースを削除する。
037 * @og.rev 4.0.0.0 (2007/10/16) DBアクセス関係のメソッドのみをパッケージ移動(hayabusa/db ⇒ fukurou/db)
038 * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue クラスで、ResultSet から値を取得する処理を移植
039 *
040 * @og.group DB/Shell制御
041 *
042 * @version  4.0
043 * @author   Kazuhiko Hasegawa
044 * @since    JDK5.0,
045 */
046public final class DBUtil {
047        /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ  {@value} */
048        private static final int DB_FETCH_SIZE = 1001 ;
049
050        /**
051         * インスタンスを作らないので、コンストラクタは、private に設定します。
052         */
053        private DBUtil() {}
054
055        /**
056         * 初期データベースに接続して、Queryを実行します(互換性確保のため残しています)。
057         *
058         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
059         * 結果は,すべて文字列に変換されて格納されます。
060         *
061         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
062         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
063         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
064         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
065         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
066         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
067         *
068         * @param   stmt ステートメント文字列
069         * @param   args オブジェクトの引数配列
070         * @param   appInfo アプリ情報オブジェクト
071         *
072         * @return  検索結果の配列
073         */
074        public static String[][] dbExecute( final String stmt ,final String[] args ,final ApplicationInfo appInfo ) {
075                try( final Transaction tran = new TransactionReal( appInfo ) ) {
076                        return dbExecute( stmt, args, tran, null, false );
077                }
078        }
079
080        /**
081         * 初期データベースに接続して、Queryを実行します(Transaction 対応)。
082         *
083         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
084         * 結果は,すべて文字列に変換されて格納されます。
085         * ここでは、Transactionオブジェクトから、Connection を取り出して使用します。
086         *
087         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
088         *
089         * @param   stmt ステートメント文字列
090         * @param   args オブジェクトの引数配列
091         * @param   tran Transactionオブジェクト
092         *
093         * @return  検索結果の配列
094         */
095        public static String[][] dbExecute( final String stmt ,final String[] args ,final Transaction tran ) {
096                return dbExecute( stmt, args, tran, null, false );
097        }
098
099        /**
100         * 検索するデータベースを指定して、Queryを実行します(互換性確保のため残しています)。
101         *
102         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
103         * 結果は,すべて文字列に変換されて格納されます。
104         * 追加:検索以外のSQLも実行できます。結果は、null を返します。
105         *
106         * @og.rev 3.0.0.0 (2002/12/25) 検索のみのクエリーから、何でもありのクエリーに変更
107         * @og.rev 2.3.1.3 (2003/01/28) Open Cursor が、大量に残る件の対応。ResultSet を close()
108         * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ+Queryに変更します。
109         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
110         * @og.rev 4.0.0.1 (2007/12/03) try ~ catch ~ finally をきちんと行う。
111         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
112         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
113         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
114         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
115         *
116         * @param   stmt ステートメント文字列
117         * @param   args オブジェクトの引数配列
118         * @param   appInfo アプリ情報オブジェクト
119         * @param   dbid 接続先ID
120         *
121         * @return  検索結果の配列
122         */
123        public static String[][] dbExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo, final String dbid ) {
124                try( final Transaction tran = new TransactionReal( appInfo ) ) {
125                        return dbExecute( stmt, args, tran, dbid, false  );
126                }
127        }
128
129        /**
130         * 検索するデータベースを指定して、Queryを実行します(Transaction 対応)。
131         *
132         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
133         * 結果は,すべて文字列に変換されて格納されます。
134         * 追加:検索以外のSQLも実行できます。結果は、null を返します。
135         * ここでは、Transactionオブジェクトから、Connection を取り出して使用します。
136         *
137         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
138         *
139         * @param   stmt ステートメント文字列
140         * @param   args オブジェクトの引数配列
141         * @param   tran Transactionオブジェクト
142         * @param   dbid 接続先ID
143         *
144         * @return  検索結果の配列
145         */
146        public static String[][] dbExecute( final String stmt ,final String[] args, final Transaction tran , final String dbid ) {
147                return dbExecute( stmt, args, tran, dbid, false );
148        }
149
150        /**
151         * 検索するデータベースを指定して、Queryを実行します(互換性確保のため残しています)。
152         *
153         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
154         * 結果は,すべて文字列に変換されて格納されます。
155         * 追加:検索以外のSQLも実行できます。結果は、null を返します。
156         *
157         * @og.rev 4.3.7.0 (2009/06/01) 新規作成
158         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
159         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
160         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
161         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
162         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
163         *
164         * @param   stmt ステートメント文字列
165         * @param   args オブジェクトの引数配列
166         * @param   appInfo アプリ情報オブジェクト
167         * @param   dbid 接続先ID
168         * @param   useHeader 1行目にヘッダーを含めるか
169         *
170         * @return  検索結果の配列
171         */
172        public static String[][] dbExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo, final String dbid, final boolean useHeader ) {
173                try( final Transaction tran = new TransactionReal( appInfo ) ) {
174                        return dbExecute( stmt, args, tran, dbid, useHeader );
175                }
176        }
177
178        /**
179         * 検索するデータベースを指定して、Queryを実行します(Transaction 対応)。
180         *
181         * ステートメントと引数により、Prepared クエリーの検索のみ実行します。
182         * 結果は,すべて文字列に変換されて格納されます。
183         * 追加:検索以外のSQLも実行できます。結果は、null を返します。
184         *
185         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
186         * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
187         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応
188         * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。
189         * @og.rev 6.4.3.2 (2016/02/19) args が null でなく、length==0 でない場合のみ、処理する。
190         * @og.rev 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズを設定。
191         *
192         * @param   stmt ステートメント文字列
193         * @param   args オブジェクトの引数配列
194         * @param   tran Transactionオブジェクト
195         * @param   dbid 接続先ID
196         * @param   useHeader 1行目にヘッダーを含めるか
197         *
198         * @return  検索結果の配列
199         */
200        public static String[][] dbExecute( final String stmt ,final String[] args, final Transaction tran, final String dbid, final boolean useHeader ) {
201                String[][] rtn = null;
202                try {
203                        final Connection conn = tran.getConnection( dbid );                             // 5.1.9.0 (2010/08/01) Transaction 対応
204                        try( final PreparedStatement pstmt = conn.prepareStatement( stmt ) ) {
205                                pstmt.setFetchSize( DB_FETCH_SIZE );                            // 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ
206
207                                // 6.4.3.2 (2016/02/19) args が null でなく、length==0 でない場合のみ、処理する。
208                                if( args != null && args.length > 0 ) {
209                                        // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
210                                        final boolean useParamMetaData = ConnectionFactory.useParameterMetaData( dbid );        // 5.3.8.0 (2011/08/01)
211                                        if( useParamMetaData ) {
212                                                final ParameterMetaData pMeta = pstmt.getParameterMetaData();
213                                                for( int i=0; i<args.length; i++ ) {
214                                                        final int type = pMeta.getParameterType( i+1 );
215                                                        // 5.3.8.0 (2011/08/01) setNull 対応
216                                                        final String val = args[i];
217                                                        if( val == null || val.isEmpty() ) {
218                                                                pstmt.setNull( i+1, type );
219                                                        }
220                                                        else {
221                                                                pstmt.setObject( i+1, val, type );
222                                                        }
223                                                }
224                                        }
225                                        else {
226                                                for( int i=0; i<args.length; i++ ) {
227                                                        pstmt.setObject( i+1,args[i] );
228                                                }
229                                        }
230                                }
231                                if( pstmt.execute() ) {                                                                 // 6.1.0.0 (2014/12/26) refactoring
232                                        try( final ResultSet resultSet = pstmt.getResultSet() ) {
233                                                rtn = DBUtil.resultToArray( resultSet,useHeader );      // 4.3.7.0 (2009/06/01)
234                                        }
235                                }
236                                // 6.3.6.1 (2015/08/28) 検索・登録関係なく、commit() する。
237                                        tran.commit();                  // 5.1.9.0 (2010/08/01) Transaction 対応
238                        }
239                }
240                catch( final SQLException ex ) {
241                        tran.rollback();                        // 5.1.9.0 (2010/08/01) Transaction 対応
242                        final String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR
243                                                        + "SQL=[" + stmt + "]" + CR
244                                                        + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR
245                                                        + "DBID=[" + dbid + "]" + CR;
246                        throw new OgRuntimeException( errMsg,ex );
247                }
248                return rtn;
249        }
250
251        /**
252         * 初期データベースに接続して、CallableStatement(PL/SQL)を実行します(互換性確保のため残しています)。
253         * ステートメントと引数により、CallableStatement クエリーを実行します。
254         * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に
255         * 設定して返します。
256         * ステートメント文字列には、 { call PLSQL( ?,?,?・・・ ) } となります。
257         * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。
258         * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。
259         *
260         * @og.rev 3.8.0.0 (2005/06/07) 新規追加
261         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
262         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
263         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
264         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
265         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
266         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
267         *
268         * @param   stmt ステートメント文字列
269         * @param   args オブジェクトの引数配列
270         * @param   appInfo アプリ情報オブジェクト
271         *
272         * @return  実行結果([0]=ステータス、[1]=エラーメッセージ
273         */
274        public static String[] dbCallExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo ) {
275                try( final Transaction tran = new TransactionReal( appInfo ) ) {
276                        return dbCallExecute( stmt ,args, tran, null );
277                }
278        }
279
280        /**
281         * 初期データベースに接続して、CallableStatement(PL/SQL)を実行します(Transaction 対応)。
282         * ステートメントと引数により、CallableStatement クエリーを実行します。
283         * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に
284         * 設定して返します。
285         * ステートメント文字列には、 { call PLSQL( ?,?,?・・・ ) } となります。
286         * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。
287         * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。
288         *
289         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
290         *
291         * @param   stmt ステートメント文字列
292         * @param   args オブジェクトの引数配列
293         * @param   tran Transactionオブジェクト
294         *
295         * @return  実行結果([0]=ステータス、[1]=エラーメッセージ
296         */
297        public static String[] dbCallExecute( final String stmt ,final String[] args, final Transaction tran ) {
298                return dbCallExecute( stmt ,args, tran, null );
299        }
300
301        /**
302         * 検索するデータベースを指定して、CallableStatement(PL/SQL)を実行します(互換性確保のため残しています)。
303         * ステートメントと引数により、CallableStatement クエリーを実行します。
304         * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に
305         * 設定して返します。
306         * ステートメント文字列には、 { call PLSQL( ?,?,?・・・ ) } となります。
307         * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。
308         * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。
309         * 検索するデータベースは、DEFAULT です。
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.1 (2007/12/03) try ~ catch ~ finally をきちんと行う。
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         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
318         *
319         * @param   stmt ステートメント文字列
320         * @param   args オブジェクトの引数配列
321         * @param   appInfo アプリ情報オブジェクト
322         * @param   dbid 接続先ID
323         *
324         * @return  実行結果([0]=ステータス、[1]=エラーメッセージ
325         */
326        public static String[] dbCallExecute( final String stmt ,final String[] args, final ApplicationInfo appInfo ,final String dbid ) {
327                try( final Transaction tran = new TransactionReal( appInfo ) ) {
328                        return dbCallExecute( stmt ,args, tran, dbid );
329                }
330        }
331
332        /**
333         * 検索するデータベースを指定して、CallableStatement(PL/SQL)を実行します(Transaction 対応)。
334         * ステートメントと引数により、CallableStatement クエリーを実行します。
335         * 結果は,ステータスとエラーメッセージを返します。便宜的に、String配列に
336         * 設定して返します。
337         * ステートメント文字列には、 { call PLSQL( ?,?,?・・・ ) } となります。
338         * 第一引数、第二引数は、OUT属性で、結果(STATUS)とエラー時の内容(ERR_CODE)を返します。
339         * 第三引数以降の ? には、オブジェクトの引数配列 が順に割り当てられます。
340         * 検索するデータベースは、DEFAULT です。
341         *
342         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
343         * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
344         * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。
345         * @og.rev 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズを設定。
346         *
347         * @param   stmt ステートメント文字列
348         * @param   args オブジェクトの引数配列
349         * @param   tran Transactionオブジェクト
350         * @param   dbid 接続先ID
351         *
352         * @return  実行結果([0]=ステータス、[1]=エラーメッセージ
353         */
354        public static String[] dbCallExecute( final String stmt ,final String[] args, final Transaction tran ,final String dbid ) {
355
356                String[] rtn = new String[2] ;
357
358                try {
359                        final Connection conn = tran.getConnection( dbid );                             // 5.1.9.0 (2010/08/01) Transaction 対応
360                        try( final CallableStatement callStmt = conn.prepareCall( stmt ) ) {
361                                callStmt.setFetchSize( DB_FETCH_SIZE );                                         // 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ
362
363                                callStmt.registerOutParameter( 1, Types.INTEGER );
364                                callStmt.registerOutParameter( 2, Types.VARCHAR );
365                                if( args != null ) {
366                                        for( int i=0; i<args.length; i++ ) {
367                                                callStmt.setObject( i+3,args[i] );
368                                        }
369                                }
370                                callStmt.execute();
371
372                                rtn[0] = String.valueOf( callStmt.getInt(1) );  // 結果ステータス
373                                rtn[1] = callStmt.getString(2);                                 // 内容(エラーメッセージ)
374
375                                tran.commit();                                  // 5.1.9.0 (2010/08/01) Transaction 対応
376                        }
377                }
378                catch( final SQLException ex ) {
379                        tran.rollback();                                // 5.1.9.0 (2010/08/01) Transaction 対応
380                        final String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR
381                                                        + "SQL=[" + stmt + "]" + CR
382                                                        + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR
383                                                        + "DBID=[" + dbid + "]" + CR;
384                        throw new OgRuntimeException( errMsg,ex );
385                }
386                return rtn;
387        }
388
389        /**
390         * SQL文の実行結果において、データの件数を取得します(互換性確保のため残しています)。
391         * ステートメントと引数により、Prepared クエリーの検索を実行します。
392         * 結果は、件数を数値で返します。
393         * あくまで、存在チェックに必要な処理のみ行っているため、通常の検索より高速です。
394         *
395         * @og.rev 3.5.0.0 (2003/09/17) 新規作成
396         * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ+Queryに変更します。
397         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
398         * @og.rev 4.0.0.1 (2007/12/03) try ~ catch ~ finally をきちんと行う。
399         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
400         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
401         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
402         * @og.rev 5.3.8.0 (2011/08/01) TransactionReal と close() 処理をセットで実行する。
403         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
404         *
405         * @param   stmt ステートメント文字列
406         * @param   args オブジェクトの引数配列
407         * @param   appInfo アプリ情報オブジェクト
408         * @param   dbid 接続先ID
409         *
410         * @return  検索結果(データの件数)
411         */
412        public static int dbExist( final String stmt ,final String[] args, final ApplicationInfo appInfo , final String dbid ) {
413                try( final Transaction tran = new TransactionReal( appInfo ) ) {
414                        return dbExist( stmt ,args, tran , dbid );
415                }
416        }
417
418        /**
419         * SQL文の実行結果において、データの件数を取得します(Transaction 対応)。
420         * ステートメントと引数により、Prepared クエリーの検索を実行します。
421         * 結果は、件数を数値で返します。
422         * あくまで、存在チェックに必要な処理のみ行っているため、通常の検索より高速です。
423         *
424         * @og.rev 5.1.9.0 (2010/08/01) 新規作成 Transaction 対応
425         * @og.rev 5.3.8.0 (2011/08/01) Transaction を引数で受け取った場合は、close() しない。
426         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応
427         * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。
428         * @og.rev 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズを設定。
429         *
430         * @param   stmt ステートメント文字列
431         * @param   args オブジェクトの引数配列
432         * @param   tran Transactionオブジェクト
433         * @param   dbid 接続先ID
434         *
435         * @return  検索結果(データの件数)
436         */
437        public static int dbExist( final String stmt ,final String[] args, final Transaction tran , final String dbid ) {
438                int rtnCnt = -1;
439
440                try {
441                        final Connection conn = tran.getConnection( dbid );                             // 5.1.9.0 (2010/08/01) Transaction 対応
442                        try( final PreparedStatement pstmt = conn.prepareStatement( stmt ) ) {
443                                pstmt.setFetchSize( DB_FETCH_SIZE );                                            // 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ
444                                if( args != null ) {
445                                        // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
446                                        final boolean useParamMetaData = ConnectionFactory.useParameterMetaData( dbid );        // 5.3.8.0 (2011/08/01)
447                                        if( useParamMetaData ) {
448                                                final ParameterMetaData pMeta = pstmt.getParameterMetaData();
449                                                for( int i=0; i<args.length; i++ ) {
450                                                        final int type = pMeta.getParameterType( i+1 );
451                                                        // 5.3.8.0 (2011/08/01) setNull 対応
452                                                        final String val = args[i];
453                                                        if( val == null || val.isEmpty() ) {
454                                                                pstmt.setNull( i+1, type );
455                                                        }
456                                                        else {
457                                                                pstmt.setObject( i+1, val, type );
458                                                        }
459                                                }
460                                        }
461                                        else {
462                                                for( int i=0; i<args.length; i++ ) {
463                                                        pstmt.setObject( i+1,args[i] );
464                                                }
465                                        }
466                                }
467                                try( final ResultSet resultSet = pstmt.executeQuery() ) {
468                                        if( resultSet.next() ) {
469                                                rtnCnt = resultSet.getInt(1);
470                                        }
471                                }
472                        }
473                        tran.commit();                          // 6.3.6.1 (2015/08/28) 検索・登録関係なく、commit() する。
474                }
475                catch( final SQLException ex ) {
476                        tran.rollback();                        // 6.3.6.1 (2015/08/28) 検索・登録関係なく処理する。
477                        final String errMsg = ex.getMessage() + ":" + ex.getSQLState() + CR
478                                                        + "SQL=[" + stmt + "]" + CR
479                                                        + "ARG=[" + StringUtil.array2csv( args ) + "]" + CR
480                                                        + "DBID=[" + dbid + "]" + CR;
481                        throw new OgRuntimeException( errMsg,ex );              // 3.5.5.4 (2004/04/15) 引数の並び順変更
482                }
483                return rtnCnt;
484        }
485
486        /**
487         * ResultSet より、結果の文字列配列を作成します。
488         *
489         * 結果は,すべて文字列に変換されて格納されます。
490         * 移動したメソッドで使われているのでこれも移動
491         *
492         * @og.rev 3.1.0.0 (2003/03/20) Vector を使用している箇所で、非同期でも構わない箇所を、ArrayList に置換え。
493         * @og.rev 3.8.0.8 (2005/10/03) エラーメッセージの出力順をメッセージ+Queryに変更します。
494         * @og.rev 4.0.0.0 (2005/01/31) private ⇒ public , ヘッダー情報の取得有無フラグの追加
495         * @og.rev 5.6.7.0 (2013/07/27) CLOB 対応
496         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue クラスで、ResultSet から値を取得する処理を行う。
497         *
498         * @param   resultSet ResultSetオブジェクト
499         * @param   useHeader true:ヘッダーを第一行に含める/false:含めない
500         *
501         * @return  ResultSetの検索結果配列
502         * @throws      java.sql.SQLException データベース・アクセス・エラーが発生した場合
503         */
504        public static String[][] resultToArray( final ResultSet resultSet,final boolean useHeader ) throws SQLException {
505                final ArrayList<String[]> data = new ArrayList<>();
506
507                final ResultSetValue rsv = new ResultSetValue( resultSet );
508
509                if( useHeader ) { data.add( rsv.getNames() ); }
510
511                while( rsv.next() ) {
512                        data.add( rsv.getValues() );
513                }
514
515                final int size = data.size();
516                String[][] rtn = new String[size][];
517                for( int i=0; i<size; i++ ) {
518                        rtn[i] = data.get(i);
519                }
520
521                return rtn;
522        }
523
524        /**
525         * コネクションオブジェクトからデータベースのProductNameを取り出します。
526         * ProductName は、小文字化して返します。
527         * また、処理エラーが発生した場合は、"none" を返します。
528         * ここでは、SQLException は、発生させません。
529         *
530         * @og.rev 5.6.7.0 (2013/07/27) 新規追加
531         * @og.rev 5.6.7.4 (2013/08/30) ProductNameの小文字化対応
532         * @og.rev 6.7.4.2 (2017/02/24) ProductNameの大文字化対応
533         *
534         * @param conn コネクションオブジェクト
535         *
536         * @return データベースのProductName
537         */
538        public static String getProductName( final Connection conn ) {
539                String dbName ;
540                try {
541                        dbName = conn.getMetaData().getDatabaseProductName().toUpperCase( Locale.JAPAN );       // 6.7.4.2 (2017/02/24)
542                }
543                catch( final SQLException ex ) {
544                        dbName = "none";
545                }
546                return dbName ;
547        }
548}