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 border="1" frame="box" rules="all" >
030 *  <caption>各データベースにおける関数</caption>
031 *  <tr><th>データベース名 </th><th>連結</th><th>部分文字列</th><th>日付関数         </th></tr>
032 *  <tr><td>{&#064;DBF.XXX}</td><td>CON </td><td>SUBSTR    </td><td>SYSDATE          </td></tr>
033 *  <tr><td>ORACLE         </td><td>||  </td><td>SUBSTR    </td><td>SYSDATE          </td></tr>
034 *  <tr><td>HSQL           </td><td>||  </td><td>SUBSTR    </td><td>CURRENT_TIMESTAMP</td></tr>
035 *  <tr><td>POSTGRES       </td><td>||  </td><td>SUBSTR    </td><td>CURRENT_DATE     </td></tr>
036 *  <tr><td>MYSQL          </td><td>||  </td><td>SUBSTR    </td><td>now()            </td></tr>
037 *  <tr><td>SQLSERVER      </td><td>+   </td><td>SUBSTRING </td><td>GETDATE()        </td></tr>
038 *  <tr><td>FIREBIRD       </td><td>||  </td><td>SUBSTR    </td><td>CURRENT_DATE     </td></tr>
039 *  <tr><td>DERBY          </td><td>||  </td><td>SUBSTR    </td><td>CURRENT_TIMESTAMP</td></tr>
040 *  <tr><td>CACHE          </td><td>||  </td><td>SUBSTRING </td><td>SYSDATE          </td></tr>
041 *  <tr><td>H2             </td><td>||  </td><td>SUBSTR    </td><td>SYSDATE          </td></tr>
042 *  <tr><td>OTHER          </td><td>||  </td><td>SUBSTR    </td><td>SYSDATE          </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 *
053 * @version  5.0
054 * @author   Kazuhiko Hasegawa
055 * @since    JDK5.0,
056 */
057public enum DBFunctionName {
058        // 引数付きenum定義:ここに、必要な関数が増えるたびに、追加していきます。
059        // 6.2.2.1 (2015/03/31) SYSDATE 項目追加
060        //                        CON   SUBSTR            SYSDATE
061          ORACLE        ( "||","SUBSTR"         , "SYSDATE" )
062        , HSQL          ( "||","SUBSTR"         , "CURRENT_TIMESTAMP" )         // 良く判らん
063        , POSTGRES      ( "||","SUBSTR"         , "CURRENT_DATE" )
064        , MYSQL         ( "||","SUBSTR"         , "now()" )                                     // SYSDATE() でもほとんど同じ
065        , SQLSERVER     ( "+" ,"SUBSTRING"      , "GETDATE()" )
066        , FIREBIRD      ( "||","SUBSTR"         , "CURRENT_DATE" )
067        , DERBY         ( "||","SUBSTR"         , "CURRENT_TIMESTAMP" )         // 6.4.9.3 (2016/08/26)
068        , CACHE         ( "||","SUBSTRING"      , "SYSDATE" )                           // 良く判らん
069        , H2            ( "||","SUBSTR"         , "SYSDATE" )                           // 6.8.3.0 (2017/11/27) 追加
070        , OTHER         ( "||","SUBSTR"         , "SYSDATE" ) ;                         // 6.4.5.0 (2016/04/08) 適当
071
072        private final String dbfCON ;
073        private final String dbfSUBSTR ;
074        private final String dbfSYSDATE ;                                                       // 6.2.2.1 (2015/03/31) SYSDATE 項目追加
075
076        /**
077         * コンストラクター(enum の場合は、private宣言される)
078         *
079         * @og.rev 5.1.4.0 (2010/03/01) 新規作成
080         * @og.rev 6.2.2.1 (2015/03/31) SYSDATE 項目追加
081         *
082         * @param       con     第1引数にて指定(CON)
083         * @param       substr  第2引数にて指定(SUBSTR)
084         * @param       sysdt   第3引数にて指定(SYSDATE)
085         */
086        private DBFunctionName( final String con , final String substr , final String sysdt ) {
087                dbfCON    = con;
088                dbfSUBSTR = substr;
089                dbfSYSDATE= sysdt;
090        }
091
092        /**
093         * 共通ファンクションに対応するデータベース個別のファンクション名を返します。
094         *
095         * 現時点では、NAME,CON,SUBSTR のみ使用できます。
096         *
097         * @og.rev 5.1.4.0 (2010/03/01) 新規作成
098         * @og.rev 6.2.2.1 (2015/03/31) SYSDATE 項目追加
099         * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の1か所にすべきです(PMD)。
100         *
101         * @param   func 共通ファンクション
102         *
103         * @return  ファンクション名
104         */
105        public String getFunctionName( final String func ) {
106
107                final String rtn ;
108                if(      "NAME".equalsIgnoreCase(    func ) ) { rtn = toString();       }
109                else if( "CON".equalsIgnoreCase(     func ) ) { rtn = dbfCON;           }
110                else if( "SUBSTR".equalsIgnoreCase(  func ) ) { rtn = dbfSUBSTR;        }
111                else if( "SYSDATE".equalsIgnoreCase( func ) ) { rtn = dbfSYSDATE;       }
112                else {                                                                                  rtn = func;                     }
113
114                return rtn ;
115        }
116
117        /**
118         * 各データベースに対応するファンクション名を返します。
119         *
120         * @og.rev 4.3.8.0 (2009/08/01) SUBSTRを追加
121         * @og.rev 5.1.2.0 (2010/01/01) MySQL対応,SUBSTRB廃止(帳票データの分割の内部処理化に伴う)
122         * @og.rev 5.1.4.0 (2010/03/01) データベース名 ではなく、dbid で判断するように変更
123         * @og.rev 5.7.7.2 (2014/06/20) DBF.NAME 時の処理の簡素化
124         * @og.rev 6.2.1.0 (2015/03/13) NAME だけ特殊処理するのではなく、統一する。
125         *
126         * @param   func ファンクション名(定義文字)
127         * @param   dbid 接続先ID
128         *
129         * @return  実ファンクション名
130         */
131        public static String getFunctionName( final String func ,final String dbid ) {
132
133                // 5.7.7.2 (2014/06/20) DBF.NAME 時の処理の簡素化
134                final String dbName = ConnectionFactory.getDBName( dbid );
135        // 6.2.1.0 (2015/03/13) NAME だけ特殊処理するのではなく、統一する。
136        //      if( "NAME".equals( func ) ) { return dbName; }
137        //      else {
138                        return getDBName( dbName ).getFunctionName( func );
139        //      }
140
141        }
142
143        /**
144         * シーケンス名よりシーケンスオブジェクトを検索し、次の値を取り出します。
145         * DBに対するシーケンスオブジェクトは予め作成されている必要があります。
146         *
147         * また、MySQLの場合は、シーケンスオブジェクトが実装されていないため、
148         * 内部的には、引数のシーケンス名と同じ名前のテーブルから、Integer型の
149         * "SEQID"という項目名を検索することにより、シーケンスをエミュレートしています。
150         *
151         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
152         * @og.rev 5.8.5.0 (2015/03/06) CACHE追加
153         * @og.rev 6.4.9.3 (2016/08/26) JavaDB(APACHE DERBY) の追加
154         *
155         * @param seqName シーケンス名
156         * @param tran トランザクション
157         *
158         * @return シーケンス番号
159         */
160        public int getSequence( final String seqName, final Transaction tran ) {
161                String sql = null;
162                // 6.0.2.5 (2014/10/31) refactoring:無効な代入です。
163                switch ( this ) {
164                        case ORACLE:
165                                sql = "select " + seqName + ".nextval from dual";
166                                break;
167                        case HSQL:
168                                sql = "select next value for " + seqName + " from dual";
169                                break;
170                        case POSTGRES:
171                                sql = "select nextval('" + seqName + "')";
172                                break;
173                        case MYSQL:
174                                sql = "update " + seqName + " set SEQID = last_insert_id(SEQID+1)";
175                                DBUtil.dbExecute( sql, new String[0], tran );
176                                sql = "select last_insert_id()";
177                                break;
178                        case SQLSERVER:
179                                throw new OgRuntimeException( "現在、SQLSERVERではシーケンス機能はサポートされていません。" );
180                        case FIREBIRD:
181                                sql = "select gen_id(" + seqName + ", 1) from rdb$database";
182                                break;
183                        // 6.4.9.3 (2016/08/26)
184                        case DERBY:
185                                throw new OgRuntimeException( "現在、DERBYではシーケンス機能はサポートされていません。" );
186                        // 5.8.5.0 (2015/03/06) CACHE追加
187                        case CACHE:
188                                throw new OgRuntimeException( "現在、CACHEではシーケンス機能はサポートされていません。" );
189                        default:
190                                throw new OgRuntimeException( "現在、このデータベースではシーケンス機能はサポートされていません。" );
191                }
192
193                // 6.0.2.5 (2014/10/31) refactoring:無効な代入です。
194                final String[][] rtn = DBUtil.dbExecute( sql, new String[0], tran );
195                return Integer.parseInt( rtn[0][0] );           // 6.0.2.4 (2014/10/17) メソッド間違い
196        }
197
198        /**
199         * 各データベースに対応するenum名を返します。
200         *
201         * @og.rev 5.1.4.0 (2010/03/01) 新規作成
202         * @og.rev 5.8.5.0 (2015/03/06) CACHE追加
203         * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の1か所にすべきです(PMD)。
204         * @og.rev 6.4.5.0 (2016/04/08) 規定以外のデータベースでも、動作するように、OTHER を用意する。
205         * @og.rev 6.4.9.3 (2016/08/26) JavaDB(APACHE DERBY) の追加
206         * @og.rev 6.8.3.0 (2017/11/27) H2 の追加
207         *
208         * @param   dbName データベース名
209         *
210         * @return  データベースに対応するenum名
211         * @og.rtnNotNull
212         */
213        public static DBFunctionName getDBName( final String dbName ) {
214                final String dbn = dbName.toUpperCase( Locale.JAPAN );
215
216                final DBFunctionName rtn ;
217                if(      dbn.contains( "ORACLE"         ) ) { rtn = DBFunctionName.ORACLE;              }
218                else if( dbn.contains( "HSQL"           ) ) { rtn = DBFunctionName.HSQL;                }
219                else if( dbn.contains( "POSTGRES"       ) ) { rtn = DBFunctionName.POSTGRES;    }
220                else if( dbn.contains( "MYSQL"          ) ) { rtn = DBFunctionName.MYSQL;               }
221                else if( dbn.contains( "SQLSERVER"      ) ) { rtn = DBFunctionName.SQLSERVER;   }
222                else if( dbn.contains( "FIREBIRD"       ) ) { rtn = DBFunctionName.FIREBIRD;    }
223                else if( dbn.contains( "DERBY"          ) ) { rtn = DBFunctionName.DERBY;               }       // 6.4.9.3 (2016/08/26)
224                else if( dbn.contains( "H2"                     ) ) { rtn = DBFunctionName.H2;                  }       // 5.8.5.0 (2015/03/06)
225                else if( dbn.contains( "CACHE"          ) ) { rtn = DBFunctionName.CACHE;               }       // 5.8.5.0 (2015/03/06)
226                else {
227                        rtn = DBFunctionName.OTHER;                     // 6.4.5.0 (2016/04/08)
228                        final String errMsg = "初期化時に、指定の dbName キーが存在しません。"
229                                                        + "[" + dbName + "] キーは、" + Arrays.toString( DBFunctionName.values() ) ;
230                        System.out.println( errMsg );
231                }
232
233                return rtn;
234        }
235}