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