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>{@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 FROM_DUAL 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 // 8.5.4.2 (2024/01/12) PMD 7.0.0 FieldNamingConventions 077// private final String dbfFROM_DUAL ; // 8.0.1.1 (2021/11/12) FROM DUAL 項目追加 078 private final String dbfFROMDUAL ; // 8.0.1.1 (2021/11/12) FROM DUAL 項目追加 079 080 /** 081 * コンストラクター(enum の場合は、private宣言される) 082 * 083 * @og.rev 5.1.4.0 (2010/03/01) 新規作成 084 * @og.rev 6.2.2.1 (2015/03/31) SYSDATE 項目追加 085 * @og.rev 8.0.1.1 (2021/11/12) FROM DUAL 項目追加 086 * 087 * @param con 第1引数にて指定(CON) 088 * @param substr 第2引数にて指定(SUBSTR) 089 * @param sysdt 第3引数にて指定(SYSDATE) 090 * @param dual 第4引数にて指定(FROM DUAL) 091 */ 092// private DBFunctionName( final String con , final String substr , final String sysdt ) { 093// DBFunctionName( final String con , final String substr , final String sysdt ) { 094 DBFunctionName( final String con , final String substr , final String sysdt , final String dual ) { 095 dbfCON = con; 096 dbfSUBSTR = substr; 097 dbfSYSDATE= sysdt; 098// dbfFROM_DUAL= dual; 099 dbfFROMDUAL= dual; // 8.5.4.2 (2024/01/12) PMD 7.0.0 100 } 101 102 /** 103 * 共通ファンクションに対応するデータベース個別のファンクション名を返します。 104 * 105 * 現時点では、NAME,CON,SUBSTR のみ使用できます。 106 * 107 * @og.rev 5.1.4.0 (2010/03/01) 新規作成 108 * @og.rev 6.2.2.1 (2015/03/31) SYSDATE 項目追加 109 * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の1か所にすべきです(PMD)。 110 * @og.rev 5.9.19.1 (2017/04/14) DBF.TYPE追加 111 * @og.rev 8.0.1.1 (2021/11/12) FROM DUAL 項目追加 112 * 113 * @param func 共通ファンクション 114 * 115 * @return ファンクション名 116 */ 117 public String getFunctionName( final String func ) { 118 119 final String rtn ; 120 if( "NAME" .equalsIgnoreCase( func ) ) { rtn = toString(); } // この、enum の NAME 121 else if( "CON" .equalsIgnoreCase( func ) ) { rtn = dbfCON; } 122 else if( "SUBSTR" .equalsIgnoreCase( func ) ) { rtn = dbfSUBSTR; } 123 else if( "SYSDATE" .equalsIgnoreCase( func ) ) { rtn = dbfSYSDATE; } 124// else if( "FROM_DUAL".equalsIgnoreCase( func ) ) { rtn = dbfFROM_DUAL; } // 8.0.1.1 (2021/11/12) 125 else if( "FROM_DUAL".equalsIgnoreCase( func ) ) { rtn = dbfFROMDUAL; } // 8.5.4.2 (2024/01/12) PMD 7.0.0 126 else if( "TYPE" .equalsIgnoreCase( func ) ) { rtn = toString().toLowerCase( Locale.JAPAN ); } // 5.9.19.1 (2017/04/14) 127 else { rtn = func; } 128 129 return rtn ; 130 } 131 132 /** 133 * 各データベースに対応するファンクション名を返します。 134 * 135 * @og.rev 4.3.8.0 (2009/08/01) SUBSTRを追加 136 * @og.rev 5.1.2.0 (2010/01/01) MySQL対応、SUBSTRB廃止(帳票データの分割の内部処理化に伴う) 137 * @og.rev 5.1.4.0 (2010/03/01) データベース名 ではなく、dbid で判断するように変更 138 * @og.rev 5.7.7.2 (2014/06/20) DBF.NAME 時の処理の簡素化 139 * @og.rev 6.2.1.0 (2015/03/13) NAME だけ特殊処理するのではなく、統一する。 140 * 141 * @param func ファンクション名(定義文字) 142 * @param dbid 接続先ID 143 * 144 * @return 実ファンクション名 145 */ 146 public static String getFunctionName( final String func ,final String dbid ) { 147 148 // 5.7.7.2 (2014/06/20) DBF.NAME 時の処理の簡素化 149 final String dbName = ConnectionFactory.getDBName( dbid ); 150 // 6.2.1.0 (2015/03/13) NAME だけ特殊処理するのではなく、統一する。 151 // if( "NAME".equals( func ) ) { return dbName; } 152 // else { 153 return getDBName( dbName ).getFunctionName( func ); 154 // } 155 } 156 157 /** 158 * シーケンス名よりシーケンスオブジェクトを検索し、次の値を取り出します。 159 * DBに対するシーケンスオブジェクトは予め作成されている必要があります。 160 * 161 * また、MySQLの場合は、シーケンスオブジェクトが実装されていないため、 162 * 内部的には、引数のシーケンス名と同じ名前のテーブルから、Integer型の 163 * "SEQID"という項目名を検索することにより、シーケンスをエミュレートしています。 164 * 165 * @og.rev 5.1.9.0 (2010/08/01) 新規追加 166 * @og.rev 5.8.5.0 (2015/03/06) CACHE追加 167 * @og.rev 5.9.31.1 (2018/04/13) DBID追加対応 168 * 169 * @param seqName シーケンス名 170 * @param tran トランザクション 171 * 172 * @return シーケンス番号 173 */ 174 public int getSequence( final String seqName, final Transaction tran ) { 175 return getSequence( seqName, tran, null ); 176 } 177 178 /** 179 * シーケンス名よりシーケンスオブジェクトを検索し、次の値を取り出します。 180 * DBに対するシーケンスオブジェクトは予め作成されている必要があります。 181 * 182 * また、MySQLの場合は、シーケンスオブジェクトが実装されていないため、 183 * 内部的には、引数のシーケンス名と同じ名前のテーブルから、Integer型の 184 * "SEQID"という項目名を検索することにより、シーケンスをエミュレートしています。 185 * 186 * @og.rev 5.1.9.0 (2010/08/01) 新規追加 187 * @og.rev 5.8.5.0 (2015/03/06) CACHE追加 188 * @og.rev 6.4.9.3 (2016/08/26) JavaDB(APACHE DERBY) の追加 189 * @og.rev 5.9.31.1 (2018/04/13) DBID追加対応 190 * @og.rev 6.9.8.0 (2018/05/28) DBID 対応漏れ、arg引数がないことを明確にするため、nullを渡します。 191 * @og.rev 8.5.4.2 (2024/01/12) PMD 7.0.0 FormalParameterNamingConventions 対応 192 * @og.rev 8.5.5.1 (2024/02/29) switch式の使用 193 * 194 * @param seqName シーケンス名 195 * @param tran トランザクション 196 * @param dbid データベースID 197 * 198 * @return シーケンス番号 199 */ 200// public int getSequence( final String seqName, final Transaction tran ) { 201// public int getSequence( final String seqName, final Transaction tran, final String DBID ) { 202 // 8.5.4.2 (2024/01/12) PMD 7.0.0 FormalParameterNamingConventions 対応 (DBID ⇒ dbid) 203 public int getSequence( final String seqName, final Transaction tran, final String dbid ) { 204 // 8.5.5.1 (2024/02/29) switch式の使用 205// String sql = null; 206// // 6.0.2.5 (2014/10/31) refactoring:無効な代入です。 207// switch ( this ) { 208// case ORACLE: 209// sql = "select " + seqName + ".nextval from dual"; 210// break; 211// case HSQL: 212// sql = "select next value for " + seqName + " from dual"; 213// break; 214// case POSTGRES: 215// sql = "select nextval('" + seqName + "')"; 216// break; 217// case MYSQL: 218// sql = "update " + seqName + " set SEQID = last_insert_id(SEQID+1)"; 219//// DBUtil.dbExecute( sql, new String[0], tran ); 220//// DBUtil.dbExecute( sql, null, tran, DBID ); // 6.9.8.0 (2018/05/28) DBID 対応漏れ 221// DBUtil.dbExecute( sql, null, tran, dbid ); // 6.9.8.0 (2018/05/28) dbid 対応漏れ 222// sql = "select last_insert_id()"; 223// break; 224// case SQLSERVER: 225// throw new OgRuntimeException( "現在、SQLSERVERではシーケンス機能はサポートされていません。" ); 226// case FIREBIRD: 227// sql = "select gen_id(" + seqName + ", 1) from rdb$database"; 228// break; 229// // 6.4.9.3 (2016/08/26) 230// case DERBY: 231// throw new OgRuntimeException( "現在、DERBYではシーケンス機能はサポートされていません。" ); 232// // 5.8.5.0 (2015/03/06) CACHE追加 233// case CACHE: 234// throw new OgRuntimeException( "現在、CACHEではシーケンス機能はサポートされていません。" ); 235// default: 236// throw new OgRuntimeException( "現在、このデータベースではシーケンス機能はサポートされていません。" ); 237// } 238 // 6.0.2.5 (2014/10/31) refactoring:無効な代入です。 239 final String sql = switch( this ) { 240 case ORACLE -> "select " + seqName + ".nextval from dual"; 241 case HSQL -> "select next value for " + seqName + " from dual"; 242 case POSTGRES -> "select nextval('" + seqName + "')"; 243 case MYSQL -> { 244 final String seqget = "update " + seqName + " set SEQID = last_insert_id(SEQID+1)"; 245// DBUtil.dbExecute( sql, new String[0], tran ); 246// DBUtil.dbExecute( sql, null, tran, DBID ); // 6.9.8.0 (2018/05/28) DBID 対応漏れ 247 DBUtil.dbExecute( seqget, null, tran, dbid ); // 6.9.8.0 (2018/05/28) dbid 対応漏れ 248 yield "select last_insert_id()"; 249 } 250 case SQLSERVER -> { 251 throw new OgRuntimeException( "現在、SQLSERVERではシーケンス機能はサポートされていません。" ); 252 } 253 case FIREBIRD -> "select gen_id(" + seqName + ", 1) from rdb$database"; // 6.4.9.3 (2016/08/26) 254 case DERBY -> { 255 throw new OgRuntimeException( "現在、DERBYではシーケンス機能はサポートされていません。" ); 256 } 257 // 5.8.5.0 (2015/03/06) CACHE追加 258 case CACHE -> { 259 throw new OgRuntimeException( "現在、CACHEではシーケンス機能はサポートされていません。" ); 260 } 261 default -> { 262 throw new OgRuntimeException( "現在、このデータベースではシーケンス機能はサポートされていません。" ); 263 } 264 }; 265 266 // 6.0.2.5 (2014/10/31) refactoring:無効な代入です。 267// final String[][] rtn = DBUtil.dbExecute( sql, new String[0], tran ); 268// final String[][] rtn = DBUtil.dbExecute( sql, new String[0], tran, DBID ); // 5.9.31.1 (2018/04/13) DBID追加対応 269// final String[][] rtn = DBUtil.dbExecute( sql, null, tran, DBID ); // 6.9.8.0 (2018/05/28) 270 final String[][] rtn = DBUtil.dbExecute( sql, null, tran, dbid ); // 6.9.8.0 (2018/05/28) 271 272 return Integer.parseInt( rtn[0][0] ); // 6.0.2.4 (2014/10/17) メソッド間違い 273 } 274 275 /** 276 * 各データベースに対応するenum名を返します。 277 * 278 * @og.rev 5.1.4.0 (2010/03/01) 新規作成 279 * @og.rev 5.8.5.0 (2015/03/06) CACHE追加 280 * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の1か所にすべきです(PMD)。 281 * @og.rev 6.4.5.0 (2016/04/08) 規定以外のデータベースでも、動作するように、OTHER を用意する。 282 * @og.rev 6.4.9.3 (2016/08/26) JavaDB(APACHE DERBY) の追加 283 * @og.rev 6.8.3.0 (2017/11/27) H2 の追加 284 * 285 * @param dbName データベース名(null不可) 286 * 287 * @return データベースに対応するenum名 288 * @og.rtnNotNull 289 */ 290 public static DBFunctionName getDBName( final String dbName ) { 291 final String dbn = dbName.toUpperCase( Locale.JAPAN ); 292 293 final DBFunctionName rtn ; 294 // 8.5.4.2 (2024/01/12) PMD 7.0.0 UnnecessaryFullyQualifiedName 295// if( dbn.contains( "ORACLE" ) ) { rtn = DBFunctionName.ORACLE; } 296// else if( dbn.contains( "HSQL" ) ) { rtn = DBFunctionName.HSQL; } 297// else if( dbn.contains( "POSTGRES" ) ) { rtn = DBFunctionName.POSTGRES; } 298// else if( dbn.contains( "MYSQL" ) ) { rtn = DBFunctionName.MYSQL; } 299// else if( dbn.contains( "SQLSERVER" ) ) { rtn = DBFunctionName.SQLSERVER; } 300// else if( dbn.contains( "FIREBIRD" ) ) { rtn = DBFunctionName.FIREBIRD; } 301// else if( dbn.contains( "DERBY" ) ) { rtn = DBFunctionName.DERBY; } // 6.4.9.3 (2016/08/26) 302// else if( dbn.contains( "CACHE" ) ) { rtn = DBFunctionName.CACHE; } // 5.8.5.0 (2015/03/06) 303// else if( dbn.contains( "H2" ) ) { rtn = DBFunctionName.H2; } // 5.8.5.0 (2015/03/06) 304 if( dbn.contains( "ORACLE" ) ) { rtn = ORACLE; } 305 else if( dbn.contains( "HSQL" ) ) { rtn = HSQL; } 306 else if( dbn.contains( "POSTGRES" ) ) { rtn = POSTGRES; } 307 else if( dbn.contains( "MYSQL" ) ) { rtn = MYSQL; } 308 else if( dbn.contains( "SQLSERVER" ) ) { rtn = SQLSERVER; } 309 else if( dbn.contains( "FIREBIRD" ) ) { rtn = FIREBIRD; } 310 else if( dbn.contains( "DERBY" ) ) { rtn = DERBY; } // 6.4.9.3 (2016/08/26) 311 else if( dbn.contains( "CACHE" ) ) { rtn = CACHE; } // 5.8.5.0 (2015/03/06) 312 else if( dbn.contains( "H2" ) ) { rtn = H2; } // 5.8.5.0 (2015/03/06) 313 else { 314// rtn = DBFunctionName.OTHER; // 6.4.5.0 (2016/04/08) 315 rtn = OTHER; // 6.4.5.0 (2016/04/08) // 8.5.4.2 (2024/01/12) PMD 7.0.0 UnnecessaryFullyQualifiedName 316 final String errMsg = "初期化時に、指定の dbName キーが存在しません。" 317// + "[" + dbName + "] キーは、" + Arrays.toString( DBFunctionName.values() ) ; 318 + "[" + dbName + "] キーは、" + Arrays.toString( values() ) ; // 8.5.4.2 (2024/01/12) PMD 7.0.0 UnnecessaryFullyQualifiedName 319 System.out.println( errMsg ); 320 } 321 322 return rtn; 323 } 324}