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