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.io.UnsupportedEncodingException;
019
020import org.opengion.fukurou.util.StringUtil;            // 6.9.8.0 (2018/05/28)
021
022/**
023 * JavaDB(derby) や、hsqldb に対する、Javaの拡張組込み関数です。
024 *
025 * staticメソッドとして、関数を定義します。引数や返り値は、各データベースの
026 * 定義に準拠します。
027 *
028 * <pre>
029 * ① JavaDB の場合
030 * 【概要】
031 *     実行するデータベースから見えるところに、ファイルを配置する必要があります。
032 *     java8 までなら、Javaのエクステンション(JAVA_HOME\)jre\lib\ext などですが、
033 *     java9以降は、CLASSPATH に設定します。
034 *     openGionでは、bin/const.bat で、OG_CLASSPATH 環境変数にパスを通して、
035 *     使用しています。
036 *     標準の Java staticメソッドを FUNCTION 定義することも出来ます。
037 * 【設定】
038 *     JavaDBに FUNCTION を定義します。(サンプル)
039 *      DROP FUNCTION TO_CHAR;
040 *
041 *      CREATE FUNCTION TO_CHAR ( VAL DOUBLE )
042 *      RETURNS VARCHAR(20)
043 *      DETERMINISTIC           -- 引数が同じなら常に同じ値を返すことを示す.(省略時はnot deterministic)
044 *      PARAMETER STYLE JAVA    -- 戻り値のタイプ
045 *      NO SQL LANGUAGE JAVA    -- 関数の中でSQLは実行しないことを示す
046 *      EXTERNAL NAME 'org.opengion.fukurou.db.Functions.toChar' ;
047 *
048 * ② HSQLDB の場合
049 * 【概要】
050 *
051 * </pre>
052 *
053 * @og.rev 6.8.5.1 (2018/01/15) org.opengion.javadb → org.opengion.fukurou.db にパッケージ変更
054 * @og.group 拡張組込み関数
055 *
056 * @version  1.1.0
057 * @author       Kazuhiko Hasegawa
058 * @since    JDK8.0,
059 */
060public final class Functions {
061    private static final String ENCODE = "UTF-8";
062
063        /**
064         *      デフォルトコンストラクターをprivateにして、
065         *      オブジェクトの生成をさせないようにする。
066         *
067         * @og.rev 6.9.7.0 (2018/05/14) 新規作成
068         */
069        private Functions() {}
070
071        /**
072         * 数値を文字列に変換します。
073         *
074         * この関数は、引数の double が、小数点を含まない場合は、
075         * 小数点以下を出しません。
076         * JavaDBの場合、数字と文字列の連結が出来ないため、文字列変換関数を用意します。
077         *
078         *      DROP FUNCTION TO_CHAR;
079         *
080         *      CREATE FUNCTION TO_CHAR ( VAL DOUBLE )
081         *      RETURNS VARCHAR(20)
082         *      DETERMINISTIC           -- 引数が同じなら常に同じ値を返すことを示す.(省略時はnot deterministic)
083         *      PARAMETER STYLE JAVA    -- 戻り値のタイプ
084         *      NO SQL LANGUAGE JAVA    -- 関数の中でSQLは実行しないことを示す
085         *      EXTERNAL NAME 'org.opengion.fukurou.db.Functions.toChar' ;
086         *
087         * @og.rev 6.7.3.0 (2017/01/27) 新規作成
088         * @og.rev 6.8.5.1 (2018/01/15) org.opengion.javadb → org.opengion.fukurou.db にパッケージ変更
089         * @og.rev 6.9.8.0 (2018/05/28) FindBugs:浮動小数点の等価性のためのテスト
090         *
091         * @param       val     文字列に変換すべき数値
092         * @return      変換した文字列
093         */
094        public static String toChar( final double val ) {
095                //  6.9.8.0 (2018/05/28) FindBugs の警告を避ける方法が、見つかりませんでした。
096                return val == (int)val ? String.valueOf( (int)val ) : String.valueOf( val );
097
098//              final int intVal = (int)val;
099//              return ((double)intVal) == val ? String.valueOf( intVal ) : String.valueOf( val );
100        }
101
102        /**
103         * 特殊な文字列の連結を行います。
104         *
105         * これは、第1引数の数字と、第2、第3、第4の文字列をスペースで連結した文字列を返します。
106         * 引数の個数が、可変に出来ないため、完全に決め打ちです。
107         *
108         *      DROP FUNCTION JOIN2;
109         *
110         *      CREATE FUNCTION JOIN2 ( INTEGER , VARCHAR(2000) , VARCHAR(2000) , VARCHAR(2000) )
111         *      RETURNS VARCHAR(4000)
112         *      DETERMINISTIC                   -- 引数が同じなら常に同じ値を返すことを示す.(省略時はnot deterministic)
113         *      PARAMETER STYLE JAVA    -- 戻り値のタイプ
114         *      NO SQL LANGUAGE JAVA    -- 関数の中でSQLは実行しないことを示す
115         *      EXTERNAL NAME 'org.opengion.fukurou.db.Functions.join2' ;
116         *
117         * @og.rev 6.7.3.0 (2017/01/27) 新規作成
118         * @og.rev 6.8.5.1 (2018/01/15) org.opengion.javadb → org.opengion.fukurou.db にパッケージ変更
119         *
120         * @param       no              第1引数の数字
121         * @param       arg2     第2引数
122         * @param       arg3    第3引数
123         * @param       arg4    第4引数
124         * @return      連結したした文字列
125         */
126        public static String join2( final int no , final String arg2 , final String arg3 , final String arg4 ) {
127                return new StringBuilder()
128                                .append( no ).append( ' ' )
129                                .append( arg2 == null ? "" : arg2 ).append( ' ' )
130                                .append( arg3 == null ? "" : arg3 ).append( ' ' )
131                                .append( arg4 == null ? "" : arg4 ).append( ' ' )
132                                .toString() ;
133        }
134
135        /**
136         * 対象の文字列の部分文字列を置換します。
137         *
138         * ただし、source、target、replacement のどれかが、null(ゼロ文字列)の場合は、
139         * 処理を実行せず、source をそのまま返します。
140         *
141         *      DROP FUNCTION REPLACE;
142         *
143         *      CREATE FUNCTION REPLACE ( VARCHAR(2000) , VARCHAR(2000) , VARCHAR(2000) )
144         *      RETURNS VARCHAR(4000)
145         *      DETERMINISTIC                   -- 引数が同じなら常に同じ値を返すことを示す.(省略時はnot deterministic)
146         *      PARAMETER STYLE JAVA    -- 戻り値のタイプ
147         *      NO SQL LANGUAGE JAVA    -- 関数の中でSQLは実行しないことを示す
148         *      EXTERNAL NAME 'org.opengion.fukurou.db.Functions.replace' ;
149         *
150         * @og.rev 6.7.3.0 (2017/01/27) 新規作成
151         * @og.rev 6.8.5.1 (2018/01/15) org.opengion.javadb → org.opengion.fukurou.db にパッケージ変更
152         * @og.rev 6.9.8.0 (2018/05/28) source、target、replacement のどれかが、null(ゼロ文字列)の場合は、source を返す。
153         *
154         * @param       source 対象の文字列
155         * @param       target 置換したい文字列
156         * @param       replacement 置換する文字列
157         * @return      置換した文字列。
158         */
159        public static String replace( final String source , final String target , final String replacement ) {
160                // 6.9.8.0 (2018/05/28) source、target、replacement のどれかが、null(ゼロ文字列)の場合は、source を返す。
161                if( StringUtil.isEmpty( source , target , replacement ) ) {             // 一つでも、null の場合、true
162                        return source;
163                }
164                else {
165                        return source.replace( target,replacement );
166                }
167
168//              if( source != null && target != null || !target.isEmpty() && replacement != null && !replacement.isEmpty() ) {
169//                      return source.replace( target,replacement );
170//              }
171//              else {
172//                      return source;
173//              }
174        }
175
176//      /**
177//       * この文字列内にあるすべてのoldCharをnewCharに置換した結果生成される文字列を返します。
178//       *
179//       * String#replace( char , char )を、繰り返します。
180//       *
181//       * @og.rev 6.7.9.0 (2017/04/28) 新規作成
182//       *
183//       * @param       source 対象の文字列
184//       * @param       target 以前の文字の集合
185//       * @param       replacement 置換する文字の集合
186//       * @return      置換した文字列。
187//       */
188//      public static String translate( final String source , final String target , final String replacement ) {
189//              String rtn = source ;
190//
191//              if( source != null && target != null && replacement != null && target.length() == replacement.length() ) {
192//                      for( int i=0; i<target.length(); i++ ) {
193//                              rtn = rtn.replace( target.charAt(i) , replacement.charAt(i) );
194//                      }
195//              }
196//
197//              return rtn;
198//      }
199
200        /**
201         * substr関数のバイト数版
202         * 過去に、hsqldb 用に作成したJava関数です。
203         *
204         * @og.rev 6.8.5.1 (2018/01/15) org.opengion.hsqldb → org.opengion.fukurou.db にパッケージ変更
205         *
206         * @param       value            変換する文字列
207         * @param       start            変換開始アドレス
208         * @param       length           変換バイト数
209         * @return      変換後文字列
210         * @throws      UnsupportedEncodingException    文字のエンコーディングがサポートされていません。
211         */
212        public static String substrb( final String value, final int start, final int length ) throws UnsupportedEncodingException {
213                String rtn = null;
214                final byte[] byteValue = makeByte( value );
215                if( byteValue != null ) {
216                        rtn = new String( byteValue,start-1,length,ENCODE );
217                }
218                return rtn;
219        }
220
221        /**
222         * length関数のバイト数版
223         * 過去に、hsqldb 用に作成したJava関数です。
224         *
225         * @og.rev 6.8.5.1 (2018/01/15) org.opengion.hsqldb → org.opengion.fukurou.db にパッケージ変更
226         *
227         * @param       value           バイト数をカウントする文字列
228         * @return      バイト数
229         * @throws      UnsupportedEncodingException    文字のエンコーディングがサポートされていません。
230         */
231        public static int lengthb( final String value ) throws UnsupportedEncodingException {
232                return makeByte( value ).length;
233        }
234
235        /**
236         * 指定の文字列をバイトコードに変換します。
237         * 引数の文字列が null の場合は、return は、byte[0] を返します。
238         *
239         * @og.rev 6.8.5.1 (2018/01/15) org.opengion.hsqldb → org.opengion.fukurou.db にパッケージ変更
240         *
241         * @param       value    変換するストリング値
242         * @param       encode   変換する文字エンコード
243         * @return      変換後文字列
244         */
245        private static byte[] makeByte( final String value ) throws UnsupportedEncodingException {
246                byte[] rtnByte = new byte[0];
247                if( value != null ) {
248                        rtnByte = value.getBytes( ENCODE );
249                }
250                return rtnByte;
251        }
252}