    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 org.opengion.fukurou.util.StringUtil;
    019import org.opengion.fukurou.system.OgRuntimeException ;                         // 6.4.2.0 (2016/01/29)
    020import org.opengion.fukurou.system.Closer;
    021import org.opengion.fukurou.model.Formatter;
    022import org.opengion.fukurou.model.ArrayDataModel;
    023import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
    024import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
    025
    026import java.sql.Connection;
    027import java.sql.PreparedStatement;
    028import java.sql.ParameterMetaData;
    029import java.sql.SQLException;
    030
    031import java.util.Arrays;
    032
    033/**
    034 * DBTableModel インターフェースを継承した TableModel の実装クラスです。
    035 * sql文を execute( query ) する事により,データベースを検索した結果を
    036 * DBTableModel に割り当てます。
    037 *
    038 * メソッドを宣言しています
    039 * DBTableModel インターフェースは，データベースの検索結果(Resultset)をラップする
    040 * インターフェースとして使用して下さい。
    041 *
    042 * @og.rev 5.2.2.0 (2010/11/01) パッケージ移動(hayabusa.db ⇒ fukurou.db)
    043 * @og.group ＤＢ/Shell制御
    044 *
    045 * @version  4.0
    046 * @author   Kazuhiko Hasegawa
    047 * @since    JDK5.0,
    048 */
    049public class DBSimpleTable {
    050
    051        private final String[]  names   ;                       // データ配列に対応するカラム配列(names)
    052        private String[]        keys            ;                       // 登録に使用するカラムキー配列(keys)
    053        private int[]           keysNo          ;                       // 登録に使用するカラムキー配列番号
    054        private String          table           ;                       // 登録テーブル名
    055        private String          where           ;                       // where 条件式[カラム名]を含む
    056        private int[]           whereNo         ;                       // [カラム名]に対応するデータ配列番号
    057        private String[]        constrain       ;                       // key に対応した制約条件
    058
    059        private String          connID          ;                       // 登録に使用するコネクションID
    060        private boolean         useWhere        ;                       // where が設定されると true にセットされます。
    061
    062        private Connection      conn            ;
    063        private PreparedStatement pstmt ;
    064        private ParameterMetaData pMeta ;                       // 5.1.2.0 (2010/01/01) setObject に、Type を渡す。(PostgreSQL対応)
    065        private String          query           ;                       // エラーメッセージ用の変数
    066        private int                     execCnt         ;
    067        private ApplicationInfo appInfo ;                       // 3.8.7.0 (2006/12/15)
    068        private boolean useParamMetaData;                       // 5.1.2.0 (2010/01/01) setObject に、Type を渡す。(PostgreSQL対応)
    069
    070        /**
    071         * データ配列のカラム名称配列を指定してオブジェクトを構築します。
    072         *
    073         * @param       nm      カラム名称配列
    074         * @throws RuntimeException tbl が null の場合
    075         */
    076        public DBSimpleTable( final String[] nm ) {
    077                if( nm == null ) {
    078                        final String errMsg = "データ配列のカラム名称に null は設定できません。";
    079                        throw new OgRuntimeException( errMsg );
    080                }
    081
    082                names = new String[nm.length];
    083                System.arraycopy( nm,0,names,0,names.length );
    084        }
    085
    086        /**
    087         * 登録に使用するカラムキー配列(keys)を登録します。
    088         *
    089         * 引数のkey配列が null の場合は、names と同じカラム名称配列(names)が使用されます。
    090         * キー配列(keys)は、一度しか登録できません。また、addConstrain等のメソッド
    091         * 呼び出しを先に実行すると、カラム名称配列(names)が設定されてしまう為、
    092         * その後にこのメソッドを呼び出すとエラーが発生します。
    093         *
    094         * @param       key     登録カラム名称配列(可変長引数)
    095         * @see         #addConstrain( String ,String )
    096         * @throws RuntimeException すでに キー配列(keys)が登録済み/作成済みの場合
    097         */
    098        public void setKeys( final String... key ) {
    099                if( keys != null ) {
    100                        final String errMsg = "すでに キー配列(keys)が登録済みです。";
    101                        throw new OgRuntimeException( errMsg );
    102                }
    103
    104                if( key != null && key.length > 0 ) {           // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    105                        final int size = key.length;
    106                        keys = new String[size];
    107                        System.arraycopy( key,0,keys,0,size );
    108
    109                        constrain = new String[size];
    110                        Arrays.fill( constrain,"?" );
    111
    112                        keysNo = new int[size];
    113                        for( int i=0; i<size; i++ ) {
    114                                final int address = findAddress( names,keys[i] );
    115                                if( address >= 0 ) {
    116                                        keysNo[i] = address;
    117                                }
    118                                else {
    119                                        final String errMsg = "指定の key は、カラム配列(names)に存在しません"
    120                                                                        + " key[" + i + "]=" + key[i]
    121                                                                        + " names=" + StringUtil.array2csv( names ) ;
    122                                        throw new OgRuntimeException( errMsg );
    123                                }
    124                        }
    125                }
    126        }
    127
    128        /**
    129         * カラム名称配列(names)と同じキー配列(keys)を作成します。
    130         *
    131         * これは、キー配列(keys) が作成されなかった場合の処理です。
    132         * keys が null の場合のみ、処理を実行します。
    133         *
    134         * @see         #setKeys( String[] )
    135         */
    136        private void makeKeys() {
    137                // キー配列(keys) が未設定の場合は、カラム名称配列(names)が設定されます。
    138                if( keys == null ) {
    139                        keys = names;
    140                        final int size = keys.length;
    141
    142                        constrain = new String[size];
    143                        Arrays.fill( constrain,"?" );
    144
    145                        keysNo = new int[size];
    146                        for( int i=0; i<size; i++ ) {
    147                                keysNo[i] = i;
    148                        }
    149                }
    150        }
    151
    152        /**
    153         * Insert/Update/Delete 時の登録するテーブル名。
    154         *
    155         * @param       tbl     テーブル名
    156         * @throws RuntimeException tbl が null の場合
    157         */
    158        public void setTable( final String tbl ) {
    159                if( tbl == null ) {
    160                        final String errMsg = "table に null は設定できません。";         // 5.1.8.0 (2010/07/01) errMsg 修正
    161                        throw new OgRuntimeException( errMsg );
    162                }
    163
    164                table = tbl;
    165        }
    166
    167        /**
    168         * データベースの接続先IDを設定します。
    169         *
    170         * @param       conn    接続先ID
    171         */
    172        public void setConnectionID( final String conn ) {
    173                connID = conn;
    174        }
    175
    176        /**
    177         * アクセスログ取得の為,ApplicationInfoオブジェクトを設定します。
    178         *
    179         * @og.rev 3.8.7.0 (2006/12/15) 新規追加
    180         *
    181         * @param   appInfo アプリ情報オブジェクト
    182         */
    183        public void setApplicationInfo( final ApplicationInfo appInfo ) {
    184                this.appInfo = appInfo;
    185        }
    186
    187        /**
    188         * Insert/Update/Delete 時の PreparedStatement の引数(クエスチョンマーク)制約。
    189         *
    190         * 制約条件(val)は、そのまま引数に使用されます。通常、？ で表される
    191         * パラメータに、文字長を制限する場合、SUBSTRB( ？,1,100 ) という
    192         * val 変数を与えます。
    193         * また、キー一つに対して、値を複数登録したい場合にも、使用できます。
    194         * 例えば、NVAL( ？,？ ) のような場合、キー一つに値２つを割り当てます。
    195         * 値配列の並び順は、キー配列(keys)に対する(？の個数)に対応します。
    196         * 注意：カラム名称配列(names)ではありません。また、先にキー配列(keys)を登録
    197         * しておかないと、キー配列登録時にエラーが発生します。
    198         * 制約条件は、処理するQUERYに対して適用されますので、
    199         * key または、val が null の場合は、RuntimeException を Throwします。
    200         *
    201         * @param       key     制約をかけるキー
    202         * @param       val     制約条件式
    203         * @see         #setKeys( String[] )
    204         * @throws RuntimeException key または、val が null の場合
    205         */
    206        public void addConstrain( final String key,final String val ) {
    207                if( key == null || val == null ) {
    208                        final String errMsg = "key または、val に null は設定できません。"
    209                                                        + " key=[" + key + "] , val=[" + val + "]" ;
    210                        throw new OgRuntimeException( errMsg );
    211                }
    212
    213                // キー配列(keys)が未設定(null)の場合は、カラム名称配列(names)を割り当てます。
    214                if( keys == null ) { makeKeys(); }
    215
    216                // 制約条件のアドレスは、カラム名称配列(names)でなく、キー配列(keys)を使用します。
    217                final int address = findAddress( keys,key );
    218                if( address >= 0 ) {
    219                        constrain[address] = val;
    220                }
    221                else {
    222                        final String errMsg = "指定の key は、キー配列(keys)に存在しません"
    223                                                        + " key=[" + key + "] , val=[" + val + "]"
    224                                                        + " keys=" + StringUtil.array2csv( keys ) ;
    225                        throw new OgRuntimeException( errMsg );
    226                }
    227        }
    228
    229        /**
    230         * Update/Delete 時のキーとなるWHERE 条件のカラム名を設定します。
    231         *
    232         * 通常の WHERE 句の書き方と同じで、カラム配列(names)に対応する設定値(values)の値を
    233         * 割り当てたい箇所に[カラム名] を記述します。文字列の場合、設定値をセットする
    234         * ときに、シングルコーテーションを使用しますが、[カラム名]で指定する場合は、
    235         * その前後に、(')シングルコーテーションは、不要です。
    236         * WHERE条件は、登録に使用するキー配列(keys)に現れない条件で行を特定することがありますので
    237         * カラム名称配列(names)を元にカラム名のアドレスを求めます。
    238         * [カラム名]は、? に置き換えて、PreparedStatement として、実行される形式に変換されます。
    239         * 例：FGJ='1' and CLM=[CLM] and SYSTEM_ID in ([SYSID],'**')
    240         *
    241         * @og.rev 4.3.4.0 (2008/12/01) キー配列(keys)が未設定(null)の場合は、カラム名称配列(names)を割り当てる
    242         * @og.rev 5.0.2.0 (2009/11/01) バグ修正(keysはデータセットのキーなので、where句のカラムに含まれて入いるわけではない)
    243         * @og.rev 6.4.1.2 (2016/01/22) PMD refactoring. where は、null をセットするのではなく、useWhere の設定で判定する。
    244         * @og.rev 6.4.3.4 (2016/03/11) Formatterに新しいコンストラクターを追加する。
    245         * @og.rev 6.9.5.0 (2018/04/23) カラム名が存在しない場合に、Exception を throw するかどうかを指定可能にする。
    246         *
    247         * @param  wh WHERE条件のカラム名
    248         * @throws RuntimeException [カラム名]がカラム配列(names)に存在しない場合
    249         */
    250        public void setWhere( final String wh ) {
    251
    252                // 6.4.1.2 (2016/01/22) PMD refactoring.
    253                if( wh == null || wh.isEmpty() ) {
    254                        useWhere= false;
    255                }
    256                else {
    257                        // キー配列(keys)が未設定(null)の場合は、カラム名称配列(names)を割り当てます。
    258                        // 5.0.2.0 (2009/11/01)
    259//                      final ArrayDataModel data = new ArrayDataModel( names );
    260                        final ArrayDataModel data = new ArrayDataModel( names,true );   // 6.9.5.0 (2018/04/23) カラム名が存在しない場合に、Exception を throw する
    261                        final Formatter format = new Formatter( data,wh );                              // 6.4.3.4 (2016/03/11)
    262                        where   = format.getQueryFormatString();
    263                        whereNo = format.getClmNos();
    264                        useWhere= true;
    265                }
    266        }
    267
    268        /**
    269         * データをインサートする場合に使用するSQL文を作成します。
    270         *
    271         * @og.rev 6.2.3.0 (2015/05/01) CSV形式の作成を、String#join( CharSequence , CharSequence... )を使用。
    272         *
    273         * @return  インサートSQL
    274         * @og.rtnNotNull
    275         */
    276        private String getInsertSQL() {
    277                // キー配列(keys)が未設定(null)の場合は、カラム名称配列(names)を割り当てます。
    278                if( keys == null ) { makeKeys(); }
    279
    280                // 6.2.3.0 (2015/05/01) CSV形式の作成を、String#join( CharSequence , CharSequence... )を使用。
    281                final StringBuilder sql = new StringBuilder( BUFFER_MIDDLE )
    282                        .append( "INSERT INTO " ).append( table )
    283                        .append( " ( " )
    284                        .append( String.join( "," , keys ) )                    // 6.2.3.0 (2015/05/01)
    285                        .append( " ) VALUES ( " )
    286                        .append( String.join( "," , constrain ) )               // 6.2.3.0 (2015/05/01)
    287                        .append( " )" );
    288
    289                useWhere = false;
    290
    291                return sql.toString();
    292        }
    293
    294        /**
    295         * データをアップデートする場合に使用するSQL文を作成します。
    296         *
    297         * @og.rev 6.4.1.2 (2016/01/22) PMD refactoring. where は、null をセットするのではなく、useWhere の設定で判定する。
    298         *
    299         * @return  アップデートSQL
    300         * @og.rtnNotNull
    301         */
    302        private String getUpdateSQL() {
    303                // キー配列(keys)が未設定(null)の場合は、カラム名称配列(names)を割り当てます。
    304                if( keys == null ) { makeKeys(); }
    305
    306                final StringBuilder sql = new StringBuilder( BUFFER_MIDDLE )
    307                        .append( "UPDATE " ).append( table ).append( " SET " )
    308                        .append( keys[0] ).append( " = " ).append( constrain[0] );
    309
    310                for( int i=1; i<keys.length; i++ ) {
    311                        sql.append( " , " )
    312                                .append( keys[i] ).append( " = " ).append( constrain[i] );
    313                }
    314
    315                // 6.4.1.2 (2016/01/22) PMD refactoring.
    316                if( useWhere ) {
    317                        sql.append( " WHERE " ).append( where );
    318                }
    319
    320                return sql.toString();
    321        }
    322
    323        /**
    324         * データをデリートする場合に使用するSQL文を作成します。
    325         *
    326         * @og.rev 5.0.2.0 (2009/11/01) バグ修正(削除時はkeysは必要ない)
    327         * @og.rev 6.4.1.2 (2016/01/22) PMD refactoring. where は、null をセットするのではなく、useWhere の設定で判定する。
    328         *
    329         * @return  デリートSQL
    330         * @og.rtnNotNull
    331         */
    332        private String getDeleteSQL() {
    333                // キー配列(keys)が未設定(null)の場合は、カラム名称配列(names)を割り当てます。
    334                // 5.0.2.0 (2009/11/01)
    335                keys = new String[0];
    336
    337                final StringBuilder sql = new StringBuilder( BUFFER_MIDDLE )
    338                        .append( "DELETE FROM " ).append( table );
    339
    340                // 6.4.1.2 (2016/01/22) PMD refactoring.
    341                if( useWhere ) {
    342                        sql.append( " WHERE " ).append( where );
    343                }
    344
    345                return sql.toString();
    346        }
    347
    348        /**
    349         * Insert 処理の開始を宣言します。
    350         * 内部的に、コネクションを接続して、PreparedStatementオブジェクトを作成します。
    351         * このメソッドと、close() メソッドは必ずセットで処理してください。
    352         *
    353         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    354         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    355         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)
    356         *
    357         * @throws SQLException Connection のオープンに失敗した場合
    358         */
    359        public void startInsert() throws SQLException {
    360                execCnt = 0;
    361                query = getInsertSQL();
    362                conn  = ConnectionFactory.connection( connID,appInfo );
    363                pstmt = conn.prepareStatement( query );
    364                // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    365                useParamMetaData = ConnectionFactory.useParameterMetaData( connID );    // 5.3.8.0 (2011/08/01)
    366                if( useParamMetaData ) {
    367                        pMeta = pstmt.getParameterMetaData();
    368                }
    369        }
    370
    371        /**
    372         * Update 処理の開始を宣言します。
    373         * 内部的に、コネクションを接続して、PreparedStatementオブジェクトを作成します。
    374         * このメソッドと、close() メソッドは必ずセットで処理してください。
    375         *
    376         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    377         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    378         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)
    379         *
    380         * @throws SQLException Connection のオープンに失敗した場合
    381         */
    382        public void startUpdate() throws SQLException {
    383                execCnt = 0;
    384                query = getUpdateSQL();
    385                conn  = ConnectionFactory.connection( connID,appInfo );
    386                pstmt = conn.prepareStatement( query );
    387                // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    388                useParamMetaData = ConnectionFactory.useParameterMetaData( connID );    // 5.3.8.0 (2011/08/01)
    389                if( useParamMetaData ) {
    390                        pMeta = pstmt.getParameterMetaData();
    391                }
    392        }
    393
    394        /**
    395         * Delete 処理の開始を宣言します。
    396         * 内部的に、コネクションを接続して、PreparedStatementオブジェクトを作成します。
    397         * このメソッドと、close() メソッドは必ずセットで処理してください。
    398         *
    399         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    400         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    401         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)
    402         *
    403         * @throws SQLException Connection のオープンに失敗した場合
    404         */
    405        public void startDelete() throws SQLException {
    406                execCnt = 0;
    407                query = getDeleteSQL();
    408                conn  = ConnectionFactory.connection( connID,appInfo );
    409                pstmt = conn.prepareStatement( query );
    410                // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    411                useParamMetaData = ConnectionFactory.useParameterMetaData( connID );    // 5.3.8.0 (2011/08/01)
    412                if( useParamMetaData ) {
    413                        pMeta = pstmt.getParameterMetaData();
    414                }
    415        }
    416
    417        /**
    418         * データ配列を渡して実際のDB処理を実行します。
    419         *
    420         * この処理の前に、startXXXX をコールしておき、INSER,UPDATE,DELETEのどの
    421         * 処理を行うか、宣言しておく必要があります。
    422         * 戻り値は、この処理での処理件数です。
    423         * 最終件数は、close( boolean ) 時に取得します。
    424         *
    425         * @og.rev 4.0.0.0 (2007/11/28) SQLException をきちんと伝播させます。
    426         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    427         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData 時の setNull 対応(PostgreSQL対応)
    428         *
    429         * @param       values  カラム配列(names)に対応する設定値配列(可変長引数)
    430         *
    431         * @return      ここでの処理件数
    432         *
    433         * @see    #close( boolean )
    434         * @throws SQLException Connection のクロースに失敗した場合
    435         * @throws RuntimeException Connection DB処理の実行に失敗した場合
    436         */
    437        public int execute( final String... values ) throws SQLException {
    438                final int cnt;
    439                try {
    440                        int clmNo = 1;  // JDBC のカラム番号は、１から始まる。
    441
    442                        // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    443                        if( useParamMetaData ) {
    444                                // keys に値を割り当てます。
    445                                for( int i=0; i<keys.length; i++ ) {
    446                                        final int type = pMeta.getParameterType( clmNo );
    447                                        // 5.3.8.0 (2011/08/01) setNull 対応
    448                                        final String val = values[keysNo[i]];
    449                                        if( val == null || val.isEmpty() ) {
    450                                                pstmt.setNull( clmNo++, type );
    451                                        }
    452                                        else {
    453                                                pstmt.setObject( clmNo++,val,type );
    454                                        }
    455                                }
    456
    457                                // where 条件を使用する場合は、値を割り当てます。
    458                                if( useWhere ) {
    459                                        for( int i=0; i<whereNo.length; i++ ) {
    460                                                final int type = pMeta.getParameterType( clmNo );
    461                                                // 5.3.8.0 (2011/08/01) setNull 対応
    462                                                final String val = values[whereNo[i]];
    463                                                if( val == null || val.isEmpty() ) {
    464                                                        pstmt.setNull( clmNo++, type );
    465                                                }
    466                                                else {
    467                                                        pstmt.setObject( clmNo++,val,type );
    468                                                }
    469                                        }
    470                                }
    471                        }
    472                        else {
    473                                // keys に値を割り当てます。
    474                                for( int i=0; i<keys.length; i++ ) {
    475                                        pstmt.setObject( clmNo++,values[keysNo[i]] );
    476                                }
    477
    478                                // where 条件を使用する場合は、値を割り当てます。
    479                                if( useWhere ) {
    480                                        for( int i=0; i<whereNo.length; i++ ) {
    481                                                pstmt.setObject( clmNo++,values[whereNo[i]] );
    482                                        }
    483                                }
    484                        }
    485
    486                        cnt = pstmt.executeUpdate();
    487                        execCnt += cnt;
    488                }
    489                catch( final SQLException ex) {
    490                        Closer.stmtClose( pstmt );
    491                        pMeta = null;           // 5.1.2.0 (2010/01/01)
    492                        if( conn != null ) {
    493                                conn.rollback();
    494                                ConnectionFactory.remove( conn,connID );
    495                                conn = null;
    496                        }
    497                        final String errMsg = "DB処理の実行に失敗しました。" + CR
    498                                                        + " query=[" + query + "]" + CR
    499                                                        + " values=" + StringUtil.array2csv( values );
    500                        throw new OgRuntimeException( errMsg ,ex );
    501                }
    502                return cnt;
    503        }
    504
    505        /**
    506         * DB処理をクロースします。
    507         *
    508         * 引数には、commit させる場合は、true を、rollback させる場合は、false をセットします。
    509         * 戻り値は、今まで処理された合計データ件数です。
    510         * この処理は、SQLException を内部で RuntimeException に変換している為、catch 節は
    511         * 不要ですが、必ず finally 節で呼び出してください。そうしないと、リソースリークの
    512         * 原因になります。
    513         *
    514         * @og.rev 5.1.2.0 (2010/01/01) pMeta のクリア
    515         *
    516         * @param  commitFlag コミットフラグ [true:commitする/false:rollbacする]
    517         *
    518         * @return      今までの合計処理件数
    519         */
    520        public int close( final boolean commitFlag ) {
    521                try {
    522//                      if( conn != null ) {                                                                                            // 8.1.1.2 (2022/02/25) Modify
    523                        if( conn != null && !conn.isClosed() ) {
    524                                if( commitFlag ) {      conn.commit();  }
    525                                else {                          conn.rollback(); }
    526                        }
    527                }
    528                catch( final SQLException ex) {
    529                        ConnectionFactory.remove( conn,connID );
    530                        conn = null;
    531                        final String errMsg = "DB処理を確定(COMMIT)できませんでした。" + CR
    532                                                        + " query=[" + query + "]" + CR ;
    533                        throw new OgRuntimeException( errMsg,ex );
    534                }
    535                finally {
    536                        Closer.stmtClose( pstmt );
    537                        pMeta = null;           // 5.1.2.0 (2010/01/01)
    538                        ConnectionFactory.close( conn,connID );
    539                        conn = null;
    540                }
    541
    542                return execCnt;
    543        }
    544
    545        /**
    546         * 文字列配列中の値とマッチするアドレスを検索します。
    547         * 文字列配列がソートされていない為、バイナリサーチが使えません。よって、
    548         * 総当りでループ検索しています。
    549         * 総数が多い場合は、遅くなる為、マップにセットして使用することを検討ください。
    550         *
    551         * @param       data    ターゲットの文字列配列中
    552         * @param       key     検索する文字列
    553         *
    554         * @return  ターゲットの添え字(存在しない場合は、-1)
    555         */
    556        private int findAddress( final String[] data,final String key ) {
    557                int address = -1;
    558                if( data != null && key != null ) {
    559                        for( int i=0; i<data.length; i++ ) {
    560                                if( key.equalsIgnoreCase( data[i] ) ) {
    561                                        address = i;
    562                                        break;
    563                                }
    564                        }
    565                }
    566                return address;
    567        }
    568}