001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.hayabusa.db;
017
018import java.sql.Connection;
019import java.sql.ResultSet;
020import java.sql.SQLException;
021
022import org.opengion.fukurou.system.HybsConst ;                  // 6.1.0.0 (2014/12/26)
023import org.opengion.fukurou.util.ErrorMessage;
024import org.opengion.fukurou.system.ThrowUtil;                                                   // 6.4.2.0 (2016/01/29)
025import org.opengion.hayabusa.common.HybsSystem;
026import org.opengion.hayabusa.common.HybsSystemException;
027import org.opengion.hayabusa.resource.ResourceManager;
028
029/**
030 * Query インターフェースを継承した Query の実装クラスです。
031 * クエリークラスにステートメントを与えて execute()することにより内部に DBTableModel を
032 * 作成します。
033 * このクラスは、Abstract クラスのため、実装は個々のサブクラスで行います。
034 * 唯一実装する必要があるのは, execute() メソッドだけです。
035 *
036 * @og.group DB検索
037 * @og.group DB登録
038 *
039 * @version  4.0
040 * @author       Kazuhiko Hasegawa
041 * @since    JDK5.0,
042 */
043public class AbstractQuery implements Query {
044        /** システムの改行コードを設定します。*/
045        protected static final String CR                 = HybsConst.CR;                        // 6.1.0.0 (2014/12/26) refactoring
046        /** StringBilderなどの初期値を設定します。   {@value} */
047        protected static final int BUFFER_MIDDLE = HybsConst.BUFFER_MIDDLE;     // 6.1.0.0 (2014/12/26) refactoring
048
049        private Connection              connection      ;
050        private int                     rtnCode         = ErrorMessage.OK;
051        private ErrorMessage    errMessage      ;
052        private ResourceManager resource        ;
053
054        private DBTableModel table                      ;
055        private String           stmtString             ;
056        private int              executeCount   = -1 ;
057        private int              skipRowCount   ;
058        private int              maxRowCount    = HybsSystem.sysInt( "DB_MAX_ROW_COUNT" ) ;
059        private boolean          updateFlag             = true ;
060        private DBEditConfig config                     ;               // 5.3.6.0 (2011/06/01)
061
062        // 5.1.9.0 (2010/08/01) DB_RETRY_COUNT,DB_RETRY_TIME 廃止
063        /** データ検索時の最大処理制限時間  {@value} */
064        protected static final int DB_MAX_QUERY_TIMEOUT = HybsSystem.sysInt( "DB_MAX_QUERY_TIMEOUT" ) ;
065
066        /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ  {@value} */
067        protected static final int DB_FETCH_SIZE                = HybsSystem.sysInt( "DB_FETCH_SIZE" ) ;
068
069        // 3.5.2.0 (2003/10/20) 内部オブジェクトタイプ名を システムパラメータ で定義します。
070        /** 内部オブジェクトタイプ名  {@value} */
071        public static final String ARG_ARRAY            = "ARG_ARRAY" ;
072        /** 内部オブジェクトタイプ名  {@value} */
073        public static final String SYSARG_ARRAY         = "SYSARG_ARRAY" ;
074        /** 内部オブジェクトタイプ名  {@value} */
075        public static final String ERR_MSG                      = "ERR_MSG" ;
076        /** 内部オブジェクトタイプ名  {@value} */
077        public static final String ERR_MSG_ARRAY        = "ERR_MSG_ARRAY" ;
078
079        /**
080         * デフォルトコンストラクター
081         *
082         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
083         */
084        protected AbstractQuery() { super(); }          // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
085
086        /**
087         * Connectionオブジェクトを外部から設定します。
088         *
089         * 通常は、Transaction と 接続先(DBID) を使用して作成した Connection を渡します。
090         * このクラスでは、Connection の close() や、ConnectionFactory への返却なども
091         * 行いません。それらは、外部処理(通常は、Transactionオブジェクト)で行います。
092         *
093         * Connection には、null は登録できません。
094         *
095         * @og.rev 6.3.6.1 (2015/08/28) 新規追加
096         *
097         * @param       conn    Connectionオブジェクト
098         */
099        public void setConnection( final Connection conn ) {
100                if( conn == null ) {
101                        final String errMsg = "Connection に null は指定できません。" + CR ;
102                        throw new HybsSystemException( errMsg );
103                }
104                connection = conn;
105        }
106
107        /**
108         * ステートメント文字列をセットします。
109         *
110         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
111         *
112         * @param       stmt ステートメント文字列
113         *
114         */
115        public void setStatement( final String stmt ) {
116                this.stmtString = stmt.trim();
117        }
118
119        /**
120         * ステートメント文字列を取り出します。
121         *
122         * @return       ステートメント文字列
123         *
124         */
125        public String getStatement() {
126                return stmtString;
127        }
128
129        /**
130         * 引数配列付のクエリーを実行します。
131         * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。
132         * これは、PreparedQuery で使用する引数を配列でセットするものです。
133         * select * from emp where deptno = ? and job = ? などの PreparedQuery や
134         * { call xxxx( ?,?,? ) } などの CallableStatement の ? 部分の引数を
135         * 順番にセットしていきます。
136         * ※ このクラスでは実装されていません。
137         *
138         * @og.rev 6.1.1.0 (2015/01/17) 引数配列を可変引数にして、execute() を含めて定義します。
139         *
140         * @param       args オブジェクトの引数配列(可変長引数)
141         */
142        public void execute( final String... args ) {                   // 6.1.1.0 (2015/01/17) refactoring
143                final String errMsg = "このクラスでは実装されていません。execute( String... )";
144                throw new UnsupportedOperationException( errMsg );
145        }
146
147        /**
148         * 引数配列付のクエリーを実行します。
149         * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。
150         * これは、PreparedQuery で使用する引数を配列でセットするものです。
151         * select * from emp where deptno = ? and job = ? などの PreparedQuery の
152         * ? 部分の引数を
153         * 順番にセットしていきます。
154         * ※ このクラスでは実装されていません。
155         *
156         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
157         *
158         * @param   keys オブジェクトのキー配列
159         * @param   args オブジェクトの引数配列(可変長引数)
160         */
161        public void execute( final String[] keys, final String... args ) {                      // 6.1.1.0 (2015/01/17) refactoring
162                final String errMsg = "このクラスでは実装されていません。execute( String[],String... )";
163                throw new UnsupportedOperationException( errMsg );
164        }
165
166        /**
167         * 引数配列付のクエリーを実行します。
168         * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。
169         * これは、PreparedQuery で使用する引数を配列でセットするものです。
170         * select * from emp where deptno = ? and job = ? などの PreparedQuery の
171         * ? 部分の引数を
172         * 順番にセットしていきます。
173         * ※ このクラスでは実装されていません。
174         *
175         * @og.rev 4.0.0.0 (2005/01/31) 引数をすべて受け取って実行するメソッドを標準メソッドとして追加
176         *
177         * @param       names           カラム名(CSV形式)
178         * @param       dbArrayType     アレイタイプ名称
179         * @param       sysArg          DBSysArg配列
180         * @param       userArg         DBUserArg配列
181         */
182        public void execute( final String names,final String dbArrayType,
183                                                final DBSysArg[] sysArg,final DBUserArg[] userArg ) {
184                final String errMsg = "このクラスでは実装されていません。execute( String,String,DBSysArg[],DBUserArg[] )";
185                throw new UnsupportedOperationException( errMsg );
186        }
187
188        /**
189         * 引数配列付のクエリーを実行します。
190         * 処理自体は, #execute() と同様に、各サブクラスの実装に依存します。
191         * これは、PreparedQuery で使用する引数を配列でセットするものです。
192         * select * from emp where deptno = ? and job = ? などの PreparedQuery の
193         * [カラム名] 部分の引数を、DBTableModelから順番にセットしていきます。
194         * ※ このクラスでは実装されていません。
195         *
196         * @param   rowNo 選択された行番号配列(登録する対象行)
197         * @param   table DBTableModelオブジェクト(登録する元データ)
198         */
199        public void execute( final int[] rowNo, final DBTableModel table ) {
200                final String errMsg = "このクラスでは実装されていません。execute( final int[] rowNo, final DBTableModel table )";
201                throw new UnsupportedOperationException( errMsg );
202        }
203
204        /**
205         * クエリーの実行結果件数をセットします。
206         * 初期値は -1 です。(クエリーが失敗した場合や,CallableStatement の呼び出し等で
207         * 実行件数が明確でない場合の戻り値)。
208         *
209         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
210         *
211         * @param       executeCount 実行結果件数
212         */
213        protected void setExecuteCount( final int executeCount ) {
214                this.executeCount = executeCount;
215        }
216
217        /**
218         * クエリーの実行結果を返します。
219         * クエリーが失敗した場合や,CallableStatement の呼び出し等で実行件数が明確でない
220         * 場合は, -1 が返されます。
221         *
222         * @return      実行結果件数
223         */
224        public int getExecuteCount() {
225                return executeCount;
226        }
227
228        /**
229         * DBTableModel をセットします。
230         * なお、検索系実行前に setDBTableModel() でテーブルをセットしていたとしても
231         * そのオブジェクトは破棄されて、新しい DBTableModel が生成されます。
232         *
233         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
234         *
235         * @param       table DBTableModelオブジェクト
236         */
237        protected void setDBTableModel( final DBTableModel table ) {
238                this.table = table;
239        }
240
241        /**
242         * 実行結果の DBTableModel を返します。
243         *
244         * @return      DBTableModelオブジェクト
245         */
246        public DBTableModel getDBTableModel() {
247                return table;
248        }
249
250        /**
251         * データベースの最大検索件数を返します。
252         *              (初期値:DB_MAX_ROW_COUNT[={@og.value SystemData#DB_MAX_ROW_COUNT}])。
253         * データベース自体の検索は,指定されたSQLの全件を検索しますが,
254         * DBTableModelのデータとして登録する最大件数をこの値に設定します。0は無制限です。
255         * サーバーのメモリ資源と応答時間の確保の為です。
256         *
257         * @return      最大検索件数
258         */
259        public int getMaxRowCount() {
260                return maxRowCount;
261        }
262
263        /**
264         * データベースの最大検索件数をセットします。
265         * データベース自体の検索は,指定されたSQLの全件を検索しますが,
266         * DBTableModelのデータとして登録する最大件数をこの値に設定します。
267         * サーバーのメモリ資源と応答時間の確保の為です。
268         * ゼロ、または、負の値を設定すると、無制限(Integer.MAX_VALUE)になります。
269         *
270         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
271         * @og.rev 4.0.0.0 (2005/08/31) ゼロ、または、負の値は、無制限(Integer.MAX_VALUE)にする。
272         *
273         * @param       maxRowCount 最大検索件数
274         */
275        public void setMaxRowCount( final int maxRowCount ) {
276                this.maxRowCount = maxRowCount > 0 ? maxRowCount : Integer.MAX_VALUE ;
277        }
278
279        /**
280         * データベースの検索スキップ件数を返します。
281         * データベース自体の検索は,指定されたSQLの全件を検索しますが,
282         * DBTableModelのデータとしては、スキップ件数分は登録されません。
283         * サーバーのメモリ資源と応答時間の確保の為です。
284         *
285         * @return      最大検索件数
286         */
287        public int getSkipRowCount() {
288                return skipRowCount;
289        }
290
291        /**
292         * データベースの検索スキップ件数をセットします。
293         * データベース自体の検索は,指定されたSQLの全件を検索しますが,
294         * DBTableModelのデータとしては、スキップ件数分は登録されません。
295         * サーバーのメモリ資源と応答時間の確保の為です。
296         *
297         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
298         *
299         * @param       skipRowCount スキップ件数
300         */
301        public void setSkipRowCount( final int skipRowCount ) {
302                this.skipRowCount = skipRowCount;
303        }
304
305        /**
306         * アップデートフラグをセットします。
307         * これは、Query で更新処理の SQL 文を実行したときにセットされます。
308         * 更新処理が実行:true / 検索処理のみ:false をセットします。
309         * このメソッドを呼び出さない場合は、デフォルト:true  です。
310         *
311         * @og.rev 2.1.2.3 (2002/12/02) データベース更新時に、更新フラグをセットするように変更
312         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
313         *
314         * @param       up      アップデートされたかどうか[true:更新処理/false:検索処理]
315         */
316        protected void setUpdateFlag( final boolean up ) {
317                updateFlag = up;
318        }
319
320        /**
321         * アップデートフラグを取得します。
322         * これは、Query で更新処理の SQL 文を実行したときに true にセットされます。
323         * 更新処理が実行:true / 検索処理のみ:false を取得できます。
324         *
325         * @og.rev 2.1.2.3 (2002/12/02) データベース更新時に、更新フラグをセットするように変更
326         * @og.rev 4.0.0.0 (2007/07/20) メソッド名変更( getUpdateFlag() ⇒ isUpdate() )
327         *
328         * @return       アップデートされたかどうか[true:更新処理/false:検索処理]
329         */
330        public boolean isUpdate() {
331                return updateFlag ;
332        }
333
334        /**
335         * リソースマネージャーをセットします。
336         * これは、言語(ロケール)に応じた DBColumn をあらかじめ設定しておく為に
337         * 必要です。
338         * リソースマネージャーが設定されていない、または、所定のキーの DBColumn が
339         * リソースに存在しない場合は、内部で DBColumn オブジェクトを作成します。
340         *
341         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
342         *
343         * @param       resource リソースマネージャー
344         */
345        public void setResourceManager( final ResourceManager resource ) {
346                this.resource = resource;
347        }
348
349        /**
350         * エラーコード を取得します。
351         * エラーコード は、ErrorMessage クラスで規定されているコードです。
352         *
353         * @return   エラーコード
354         */
355        public int getErrorCode() {
356                return rtnCode;
357        }
358
359        /**
360         * エラーコード をセットします。
361         * エラーコード は、ErrorMessage クラスで規定されているコードです。
362         *
363         * @param   cd エラーコード
364         */
365        protected void setErrorCode( final int cd ) {
366                rtnCode = cd;
367        }
368
369        /**
370         * エラーメッセージオブジェクト を取得します。
371         *
372         * @return   エラーメッセージオブジェクト
373         */
374        public ErrorMessage getErrorMessage() {
375                return errMessage;
376        }
377
378        /**
379         * エラーメッセージオブジェクト をセットします。
380         *
381         * @param   em エラーメッセージオブジェクト
382         */
383        protected void setErrorMessage( final ErrorMessage em ) {
384                errMessage = em;
385        }
386
387        /**
388         * 編集設定オブジェクトをセットします。
389         *
390         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
391         *
392         * @param config 編集設定オブジェクト
393         */
394        public void setEditConfig( final DBEditConfig config ) {
395                this.config = config;
396        }
397
398        /**
399         * 編集設定オブジェクトを取得します。
400         *
401         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
402         *
403         * @return 編集設定オブジェクト
404         */
405        protected DBEditConfig getEditConfig() {
406                return config;
407        }
408
409        //////////////////////////////////////////////////////////////////////////
410        //
411        //       継承時にサブクラスから使用するメソッド類( protected )
412        //
413        //////////////////////////////////////////////////////////////////////////
414
415        /**
416         * ResultSet を DBTableModelに割り当てます。
417         *
418         * 毎回,検索毎に,DBTableModel にコピーするイメージです。
419         * ResulSet 以外のオブジェクトから,DBTableModelを作成する場合は,
420         * このメソッドをオーバーライドします。
421         *
422         * このメソッドは, execute からのみ,呼び出されます。
423         * それ以外からは呼出し出来ません。
424         *
425         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
426         * @og.rev 3.3.3.3 (2003/08/06) カラムのラベル名を、大文字に変換する。
427         * @og.rev 3.8.5.0 (2006/03/02) CLOB カラムかどうかを判定しCLOBの場合は、Clob オブジェクトから文字列を取り出します。
428         * @og.rev 3.8.8.8 (2007/05/11) ROWID対応(小数点対応 "0.3" が ".3" と表示される対策)
429         * @og.rev 4.0.0.0 (2006/01/31) CLOB カラムかどうかを判定しCLOBの場合は、ストリームから値を取り出します。
430         * @og.rev 5.3.6.0 (2011/06/01) DBTableModel作成処理をDBTableModelUtilに移動&集計機能対応
431         * @og.rev 6.3.6.1 (2015/08/28) close(),realClose() 廃止。Queryはキャッシュしません。
432         *
433         * @param       resultSet ResultSetオブジェクト
434         */
435        protected void createTableModel( final ResultSet resultSet ) {
436                try {
437                        if( config == null ) {
438                                table = DBTableModelUtil.makeDBTable( resultSet, getSkipRowCount(), maxRowCount, resource );
439                        }
440                        else {
441                                table = DBTableModelUtil.makeEditDBTable( resultSet, getSkipRowCount(), maxRowCount, resource, config );
442                        }
443
444                        setExecuteCount( table.getRowCount() );
445                }
446                catch( final SQLException ex ) {
447                        final String errMsg = "テーブルモデルを作成できませんでした。";
448                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
449                }
450        }
451
452        /**
453         * ConnectionFactory.connection( String ); を利用して,Connection
454         * オブジェクトを取り出します。
455         *
456         * コネクションプールが一杯の場合は、即エラーになります。
457         *
458         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
459         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
460         * @og.rev 5.1.9.0 (2010/08/01) transaction 属性追加。
461         * @og.rev 6.3.6.1 (2015/08/28) transaction 属性廃止。内部のConnectionを返します。
462         *
463         * @return      コネクション
464         */
465        protected Connection getConnection() {
466
467                return connection;
468        }
469
470        /**
471         * この接続が、PreparedStatement#getParameterMetaData() を使用するかどうかを判定します。
472         *
473         * ConnectionFactory#useParameterMetaData(String) の結果を返します。(postgreSQL対応)
474         *
475         * ※ 暫定処理です。もっと、良い方法を考える必要があります。
476         *
477         * @og.rev 5.3.8.0 (2011/08/01) 新規追加
478         * @og.rev 6.3.6.1 (2015/08/28) 内部変数にconnIDが無くなったため、直接所得することになりました。
479         * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
480         *
481         * @return      使用する場合:true / その他:false
482         * @see org.opengion.fukurou.db.ConnectionFactory#useParameterMetaData(String)
483         */
484        protected boolean useParameterMetaData() {
485        //      return ConnectionFactory.useParameterMetaData( connID );
486                try {
487                        return "PostgreSQL".equalsIgnoreCase( connection.getMetaData().getDatabaseProductName() );
488                }
489                catch( final Throwable th ) {
490                        System.err.println( ThrowUtil.ogStackTrace( th ) );                             // 6.4.2.0 (2016/01/29)
491                }
492                return false ;
493        }
494
495        //////////////////////////////////////////////////////////////////////////
496        //
497        //       Object クラスのオーバーライド部分
498        //
499        //////////////////////////////////////////////////////////////////////////
500
501        /**
502         * オブジェクトの識別子として,最後のクエリーを返します。
503         *
504         * @return      最後のクエリー
505         * @og.rtnNotNull
506         */
507        @Override
508        public String toString() {
509                return  "LastQuery  :[" + getStatement() + "] ";
510        }
511}