オレオレSQL関数の作り方〜HSQLDB編〜

Seasar Conference 2008 Autumnですべらない話、じゃなくてTeeda再考を話されるよねむらさん、じゃなくて米林さんの以下のエントリがきっかけになり、オレオレSQL関数の作り方〜HSQLDB編〜という事でHSQLDBに、自作のSQL関数を組み込むやり方を簡単にめもっときます。

といっても例によって積読状態の以下の本の11章を参考にしています。

Code Reading―オープンソースから学ぶソフトウェア開発技法

Code Reading―オープンソースから学ぶソフトウェア開発技法

対象のバージョンは1.8.0.9です。本のほうはバージョン1.61ですね。

追加する関数は、世界のナベアツの【3の倍数と3がつく数字の時だけアホになる】関数です(笑)。

まずいじるソースは、org.hsqldb.Libraryのみです。

sNumericという関数名とメソッド名の2次元配列があります。

    public static final String[][] sNumeric = {
        {
            "ABS", "org.hsqldb.Library.abs"
        }, {
            "ACOS", "java.lang.Math.acos"
        }, {
            "ASIN", "java.lang.Math.asin"
...

ABSという関数の実態はorg.hsqldb.Library#absメソッドです。org.hsqldb.Library#absメソッドは下記のとおり。

    public static double abs(double d) {
        return Math.abs(d);
    }

これを参考にnabeatsu関数を追加します。

        }, {
            "ROUNDMAGIC", "org.hsqldb.Library.roundMagic"
        }, {
            "NABEATSU", "org.hsqldb.Library.nabeatsu"
        }
    };
    public static String nabeatsu(int i) {
    	if(i%3 == 0) {
    		return "アホ";
    	} else if(String.valueOf(i).indexOf("3") != -1) {
    		return "アホ";
    	} else {
    		return null;
    	}
    }

とします。

また関数に対応するint型のキーを登録します。これもabsを真似てnabeatsuを67で登録します。

    static final int abs                           = 0;
...
    static final int year                          = 66;
    static final int nabeatsu = 67;

/** @todo  see bitxor and datediff numbering */

    //
    private static final IntValueHashMap functionMap =
        new IntValueHashMap(68);
    static final Double piValue = new Double(Library.pi());

    static {
        functionMap.put("abs", abs);
        functionMap.put("ascii", ascii);
...
        functionMap.put("nabeatsu", nabeatsu);
    }

このキーがswitchで回ってくるので対応するcaseを追加します。これも他を真似る。

    static Object invoke(int fID, Object[] params) throws HsqlException {

        try {
            switch (fID) {

                case abs : {
                    return new Double(
                        Library.abs(((Number) params[0]).doubleValue()));
                }
...
                case nabeatsu : {
                	return nabeatsu(((Number) params[0]).intValue());
                }
...

全体のdiffは以下のとおり。

182a183,184
>         }, {
>             "NABEATSU", "org.hsqldb.Library.nabeatsu"
443a446,455
>     
>     public static String nabeatsu(int i) {
>     	if(i%3 == 0) {
>     		return "アホ";
>     	} else if(String.valueOf(i).indexOf("3") != -1) {
>     		return "アホ";
>     	} else {
>     		return null;
>     	}
>     }
1945a1958
>     static final int nabeatsu = 67;
1951c1964
<         new IntValueHashMap(67);
    • -
> new IntValueHashMap(68); 2023a2037 > functionMap.put("nabeatsu", nabeatsu); 2264a2279,2281 > } > case nabeatsu : { > return nabeatsu(((Number) params[0]).intValue());

ビルドして、
create table test(i int);
insert into test values(1);
select NABEATSU(3) from test;
と実行すると下記のようになる。