    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.util.Locale;
    019import java.util.Arrays;                                        // 6.3.9.1 (2015/11/27)
    020import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
    021
    022/**
    023 * 各データベースに対応するenum名を返します。
    024 * 主に、各データベースにおける関数名の差異を吸収するためのenumです。
    025 * 本来は、互換性のあるファンクション以外、使用しないようにしましょう。
    026 * また、無ければ互換性パックなどで、ファンクションを定義してしまうのも
    027 * 一つの方法です。
    028 *
    029 * <table class="plain">
    030 *  <caption>各データベースにおける関数</caption>
    031 *  <tr><th>データベース名 </th><th>連結</th><th>部分文字列</th><th>日付関数         </th><th>DUAL検索         </th></tr>
    032 *  <tr><td>{&#064;DBF.XXX}</td><td>CON </td><td>SUBSTR    </td><td>SYSDATE          </td><td>FROM_DUAL        </td></tr>
    033 *  <tr><td>ORACLE         </td><td>||  </td><td>SUBSTR    </td><td>SYSDATE          </td><td>FROM DUAL        </td></tr>
    034 *  <tr><td>HSQL           </td><td>||  </td><td>SUBSTR    </td><td>CURRENT_TIMESTAMP</td><td>FROM DUAL        </td></tr>
    035 *  <tr><td>POSTGRES       </td><td>||  </td><td>SUBSTR    </td><td>CURRENT_DATE     </td><td>                 </td></tr>
    036 *  <tr><td>MYSQL          </td><td>||  </td><td>SUBSTR    </td><td>now()            </td><td>FROM DUAL        </td></tr>
    037 *  <tr><td>SQLSERVER      </td><td>+   </td><td>SUBSTRING </td><td>GETDATE()        </td><td>                 </td></tr>
    038 *  <tr><td>FIREBIRD       </td><td>||  </td><td>SUBSTR    </td><td>CURRENT_DATE     </td><td>FROM RDB$DATABASE</td></tr>
    039 *  <tr><td>DERBY          </td><td>||  </td><td>SUBSTR    </td><td>CURRENT_TIMESTAMP</td><td>FROM SYSIBM.SYSDUMMY1</td></tr>
    040 *  <tr><td>CACHE          </td><td>||  </td><td>SUBSTRING </td><td>SYSDATE          </td><td>FROM DUAL        </td></tr>
    041 *  <tr><td>H2             </td><td>||  </td><td>SUBSTR    </td><td>SYSDATE          </td><td>FROM DUAL        </td></tr>
    042 *  <tr><td>OTHER          </td><td>||  </td><td>SUBSTR    </td><td>SYSDATE          </td><td>FROM DUAL        </td></tr>
    043 * </table>
    044 *
    045 * ※ MySQLでは、通常文字列連結は、CONCAT関数を使います。パイプ(||)で結合するには、
    046 * SET sql_mode='PIPES_AS_CONCAT' しておく必要があります。
    047 * JDBCで設定する場合は、jdbc:mysql://《サーバー》/《DB名》?sessionVariables=sql_mode='PIPES_AS_CONCAT'
    048 * と指定します。
    049 *
    050 * @og.rev 5.1.4.0 (2010/03/01) 新規作成
    051 * @og.rev 5.8.5.0 (2015/03/06) CACHE追加
    052 * @og.rev 8.0.1.1 (2021/11/12) FROM DUAL 項目追加
    053 *
    054 * @version  5.0
    055 * @author   Kazuhiko Hasegawa
    056 * @since    JDK5.0,
    057 */
    058public enum DBFunctionName {
    059        // 引数付きenum定義：ここに、必要な関数が増えるたびに、追加していきます。
    060        // 6.2.2.1 (2015/03/31) SYSDATE 項目追加
    061        //                        CON   SUBSTR            SYSDATE
    062          /** ファンクション名 */ ORACLE        ( "||" , "SUBSTR"               , "SYSDATE"                             ,"FROM DUAL" )
    063        , /** ファンクション名 */ HSQL          ( "||" , "SUBSTR"               , "CURRENT_TIMESTAMP"   ,"FROM DUAL" )  // 良く判らん
    064        , /** ファンクション名 */ POSTGRES      ( "||" , "SUBSTR"               , "CURRENT_DATE"                ,""     )
    065        , /** ファンクション名 */ MYSQL         ( "||" , "SUBSTR"               , "now()"                               ,"FROM DUAL" )  // SYSDATE() でもほとんど同じ
    066        , /** ファンクション名 */ SQLSERVER     ( "+"  , "SUBSTRING"    , "GETDATE()"                   ,""     )
    067        , /** ファンクション名 */ FIREBIRD      ( "||" , "SUBSTR"               , "CURRENT_DATE"                ,"FROM RDB$DATABASE" )
    068        , /** ファンクション名 */ DERBY         ( "||" , "SUBSTR"               , "CURRENT_TIMESTAMP"   ,"FROM SYSIBM.SYSDUMMY1" )      // 6.4.9.3 (2016/08/26)
    069        , /** ファンクション名 */ CACHE         ( "||" , "SUBSTRING"    , "SYSDATE"                             ,"FROM DUAL" )  // 良く判らん
    070        , /** ファンクション名 */ H2            ( "||" , "SUBSTR"               , "SYSDATE"                             ,"FROM DUAL" )  // 6.8.3.0 (2017/11/27) 追加
    071        , /** ファンクション名 */ OTHER         ( "||" , "SUBSTR"               , "SYSDATE"                             ,"FROM DUAL" ) ;        // 6.4.5.0 (2016/04/08) 適当
    072
    073        private final String dbfCON ;
    074        private final String dbfSUBSTR ;
    075        private final String dbfSYSDATE ;                                                       // 6.2.2.1 (2015/03/31) SYSDATE 項目追加
    076        private final String dbfFROM_DUAL ;                                                     // 8.0.1.1 (2021/11/12) FROM DUAL 項目追加
    077
    078        /**
    079         * コンストラクター(enum の場合は、private宣言される)
    080         *
    081         * @og.rev 5.1.4.0 (2010/03/01) 新規作成
    082         * @og.rev 6.2.2.1 (2015/03/31) SYSDATE 項目追加
    083         * @og.rev 8.0.1.1 (2021/11/12) FROM DUAL 項目追加
    084         *
    085         * @param       con     第１引数にて指定(CON)
    086         * @param       substr  第２引数にて指定(SUBSTR)
    087         * @param       sysdt   第３引数にて指定(SYSDATE)
    088         * @param       dual    第４引数にて指定(FROM DUAL)
    089         */
    090//      private DBFunctionName( final String con , final String substr , final String sysdt ) {
    091//      DBFunctionName( final String con , final String substr , final String sysdt ) {
    092        DBFunctionName( final String con , final String substr , final String sysdt , final String dual ) {
    093                dbfCON    = con;
    094                dbfSUBSTR = substr;
    095                dbfSYSDATE= sysdt;
    096                dbfFROM_DUAL= dual;
    097        }
    098
    099        /**
    100         * 共通ファンクションに対応するデータベース個別のファンクション名を返します。
    101         *
    102         * 現時点では、NAME,CON,SUBSTR のみ使用できます。
    103         *
    104         * @og.rev 5.1.4.0 (2010/03/01) 新規作成
    105         * @og.rev 6.2.2.1 (2015/03/31) SYSDATE 項目追加
    106         * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の１か所にすべきです(PMD)。
    107         * @og.rev 5.9.19.1 (2017/04/14) DBF.TYPE追加
    108         * @og.rev 8.0.1.1 (2021/11/12) FROM DUAL 項目追加
    109         *
    110         * @param   func 共通ファンクション
    111         *
    112         * @return  ファンクション名
    113         */
    114        public String getFunctionName( final String func ) {
    115
    116                final String rtn ;
    117                if(      "NAME"     .equalsIgnoreCase( func ) ) { rtn = toString();     }               // この、enum の NAME
    118                else if( "CON"      .equalsIgnoreCase( func ) ) { rtn = dbfCON;         }
    119                else if( "SUBSTR"   .equalsIgnoreCase( func ) ) { rtn = dbfSUBSTR;      }
    120                else if( "SYSDATE"  .equalsIgnoreCase( func ) ) { rtn = dbfSYSDATE;     }
    121                else if( "FROM_DUAL".equalsIgnoreCase( func ) ) { rtn = dbfFROM_DUAL;   }       // 8.0.1.1 (2021/11/12)
    122                else if( "TYPE"     .equalsIgnoreCase( func ) ) { rtn = toString().toLowerCase( Locale.JAPAN ); }               // 5.9.19.1 (2017/04/14)
    123                else {                                                                                  rtn = func;                     }
    124
    125                return rtn ;
    126        }
    127
    128        /**
    129         * 各データベースに対応するファンクション名を返します。
    130         *
    131         * @og.rev 4.3.8.0 (2009/08/01) SUBSTRを追加
    132         * @og.rev 5.1.2.0 (2010/01/01) MySQL対応,SUBSTRB廃止(帳票データの分割の内部処理化に伴う)
    133         * @og.rev 5.1.4.0 (2010/03/01) データベース名 ではなく、dbid で判断するように変更
    134         * @og.rev 5.7.7.2 (2014/06/20) DBF.NAME 時の処理の簡素化
    135         * @og.rev 6.2.1.0 (2015/03/13) NAME だけ特殊処理するのではなく、統一する。
    136         *
    137         * @param   func ファンクション名(定義文字)
    138         * @param   dbid 接続先ID
    139         *
    140         * @return  実ファンクション名
    141         */
    142        public static String getFunctionName( final String func ,final String dbid ) {
    143
    144                // 5.7.7.2 (2014/06/20) DBF.NAME 時の処理の簡素化
    145                final String dbName = ConnectionFactory.getDBName( dbid );
    146        // 6.2.1.0 (2015/03/13) NAME だけ特殊処理するのではなく、統一する。
    147        //      if( "NAME".equals( func ) ) { return dbName; }
    148        //      else {
    149                        return getDBName( dbName ).getFunctionName( func );
    150        //      }
    151        }
    152
    153        /**
    154         * シーケンス名よりシーケンスオブジェクトを検索し、次の値を取り出します。
    155         * DBに対するシーケンスオブジェクトは予め作成されている必要があります。
    156         *
    157         * また、MySQLの場合は、シーケンスオブジェクトが実装されていないため、
    158         * 内部的には、引数のシーケンス名と同じ名前のテーブルから、Integer型の
    159         * "SEQID"という項目名を検索することにより、シーケンスをエミュレートしています。
    160         *
    161         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
    162         * @og.rev 5.8.5.0 (2015/03/06) CACHE追加
    163         * @og.rev 5.9.31.1 (2018/04/13) DBID追加対応
    164         *
    165         * @param seqName シーケンス名
    166         * @param tran トランザクション
    167         *
    168         * @return シーケンス番号
    169         */
    170        public int getSequence( final String seqName, final Transaction tran ) {
    171                return getSequence( seqName, tran, null );
    172        }
    173
    174        /**
    175         * シーケンス名よりシーケンスオブジェクトを検索し、次の値を取り出します。
    176         * DBに対するシーケンスオブジェクトは予め作成されている必要があります。
    177         *
    178         * また、MySQLの場合は、シーケンスオブジェクトが実装されていないため、
    179         * 内部的には、引数のシーケンス名と同じ名前のテーブルから、Integer型の
    180         * "SEQID"という項目名を検索することにより、シーケンスをエミュレートしています。
    181         *
    182         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
    183         * @og.rev 5.8.5.0 (2015/03/06) CACHE追加
    184         * @og.rev 6.4.9.3 (2016/08/26) JavaDB(APACHE DERBY) の追加
    185         * @og.rev 5.9.31.1 (2018/04/13) DBID追加対応
    186         * @og.rev 6.9.8.0 (2018/05/28) DBID 対応漏れ,arg引数がないことを明確にするため、nullを渡します。
    187         *
    188         * @param seqName シーケンス名
    189         * @param tran トランザクション
    190         * @param DBID DBID
    191         *
    192         * @return シーケンス番号
    193         */
    194//      public int getSequence( final String seqName, final Transaction tran ) {
    195        public int getSequence( final String seqName, final Transaction tran, final String DBID ) {
    196                String sql = null;
    197                // 6.0.2.5 (2014/10/31) refactoring:無効な代入です。
    198                switch ( this ) {
    199                        case ORACLE:
    200                                sql = "select " + seqName + ".nextval from dual";
    201                                break;
    202                        case HSQL:
    203                                sql = "select next value for " + seqName + " from dual";
    204                                break;
    205                        case POSTGRES:
    206                                sql = "select nextval('" + seqName + "')";
    207                                break;
    208                        case MYSQL:
    209                                sql = "update " + seqName + " set SEQID = last_insert_id(SEQID+1)";
    210//                              DBUtil.dbExecute( sql, new String[0], tran );
    211                                DBUtil.dbExecute( sql, null, tran, DBID );              // 6.9.8.0 (2018/05/28) DBID 対応漏れ
    212                                sql = "select last_insert_id()";
    213                                break;
    214                        case SQLSERVER:
    215                                throw new OgRuntimeException( "現在、SQLSERVERではシーケンス機能はサポートされていません。" );
    216                        case FIREBIRD:
    217                                sql = "select gen_id(" + seqName + ", 1) from rdb$database";
    218                                break;
    219                        // 6.4.9.3 (2016/08/26)
    220                        case DERBY:
    221                                throw new OgRuntimeException( "現在、DERBYではシーケンス機能はサポートされていません。" );
    222                        // 5.8.5.0 (2015/03/06) CACHE追加
    223                        case CACHE:
    224                                throw new OgRuntimeException( "現在、CACHEではシーケンス機能はサポートされていません。" );
    225                        default:
    226                                throw new OgRuntimeException( "現在、このデータベースではシーケンス機能はサポートされていません。" );
    227                }
    228
    229                // 6.0.2.5 (2014/10/31) refactoring:無効な代入です。
    230//              final String[][] rtn = DBUtil.dbExecute( sql, new String[0], tran );
    231//              final String[][] rtn = DBUtil.dbExecute( sql, new String[0], tran, DBID );              // 5.9.31.1 (2018/04/13) DBID追加対応
    232                final String[][] rtn = DBUtil.dbExecute( sql, null, tran, DBID );                               // 6.9.8.0 (2018/05/28)
    233
    234                return Integer.parseInt( rtn[0][0] );           // 6.0.2.4 (2014/10/17) メソッド間違い
    235        }
    236
    237        /**
    238         * 各データベースに対応するenum名を返します。
    239         *
    240         * @og.rev 5.1.4.0 (2010/03/01) 新規作成
    241         * @og.rev 5.8.5.0 (2015/03/06) CACHE追加
    242         * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の１か所にすべきです(PMD)。
    243         * @og.rev 6.4.5.0 (2016/04/08) 規定以外のデータベースでも、動作するように、OTHER を用意する。
    244         * @og.rev 6.4.9.3 (2016/08/26) JavaDB(APACHE DERBY) の追加
    245         * @og.rev 6.8.3.0 (2017/11/27) H2 の追加
    246         *
    247         * @param   dbName データベース名(null不可)
    248         *
    249         * @return  データベースに対応するenum名
    250         * @og.rtnNotNull
    251         */
    252        public static DBFunctionName getDBName( final String dbName ) {
    253                final String dbn = dbName.toUpperCase( Locale.JAPAN );
    254
    255                final DBFunctionName rtn ;
    256                if(      dbn.contains( "ORACLE"         ) ) { rtn = DBFunctionName.ORACLE;              }
    257                else if( dbn.contains( "HSQL"           ) ) { rtn = DBFunctionName.HSQL;                }
    258                else if( dbn.contains( "POSTGRES"       ) ) { rtn = DBFunctionName.POSTGRES;    }
    259                else if( dbn.contains( "MYSQL"          ) ) { rtn = DBFunctionName.MYSQL;               }
    260                else if( dbn.contains( "SQLSERVER"      ) ) { rtn = DBFunctionName.SQLSERVER;   }
    261                else if( dbn.contains( "FIREBIRD"       ) ) { rtn = DBFunctionName.FIREBIRD;    }
    262                else if( dbn.contains( "DERBY"          ) ) { rtn = DBFunctionName.DERBY;               }       // 6.4.9.3 (2016/08/26)
    263                else if( dbn.contains( "CACHE"          ) ) { rtn = DBFunctionName.CACHE;               }       // 5.8.5.0 (2015/03/06)
    264                else if( dbn.contains( "H2"                     ) ) { rtn = DBFunctionName.H2;                  }       // 5.8.5.0 (2015/03/06)
    265                else {
    266                        rtn = DBFunctionName.OTHER;                     // 6.4.5.0 (2016/04/08)
    267                        final String errMsg = "初期化時に、指定の dbName キーが存在しません。"
    268                                                        + "[" + dbName + "] キーは、" + Arrays.toString( DBFunctionName.values() ) ;
    269                        System.out.println( errMsg );
    270                }
    271
    272                return rtn;
    273        }
    274}