« ますます快適になったN1ライフ | メイン | ドコモのSPモードを考える »

Hibernateでビット演算子を利用する

ASPの機能拡張をしていたところ、HibernateではSQL文にビット演算子が使えないことが判明。
色々と調べてみたが、日本語での解説がなかったので、参考までに記録しておく。

まず、Hibernateの2.xではビット演算子がサポートされていた(ようだ)が、3.xからサポートされないとのこと。
そこで、ビット演算をユーザ関数として定義し、データベースへの接続を行うDialectをオーバーラップして、直接SQL文を吐き出すようにするとよいらしい。
と、ここまでの内容でなるほど!と思った方はすでにご自分で解決できるだろうし、そもそも書いている僕自身がこれじゃさっぱりわからないw。

では具体的な対策を説明していきます。
調べる内容は概ね次の通り。

  1. Hibernateで利用しているデータベースがビット演算子をサポートしていること。
  2. サポートしているビット演算子(通常は'&'とか)
  3. Hibernate内における利用しているデータベースのDialectのクラス名

1.と2.は大丈夫ですよね。ちなみに僕の環境はSQLServer2005ですが、ビット演算子(AND)は「&」です。
3.については、Hibernateのコンフィグレーションファイル(「hibernate.cfg.xml」など、データベースの接続情報を記載するxmlファイルがあるよね、あれです)に書かれているdialectプロパティを見ると分かります。ちなみにSQLServerは、「org.hibernate.dialect.SQLServer」でした。

で、実際には2つクラスファイルを作成する必要があります。以下、SQLServerを例に説明するので、他のデータベースを使っている人は適宜読み替えましょう。

まずは1つ目のクラス「SQLServerDialect.java」。
クラス名は、先程3.で調べたものと併せておきます。

packageパッケージ名;

import org.hibernate.Hibernate;

public class SQLServerDialect extends org.hibernate.dialect.SQLServerDialect {
    public SQLServerDialect() {
        super();
        registerFunction("bitwise_and",    new BitwiseAndFunction("bitwise_and", Hibernate.INTEGER));
    }
}

ポイントは、先程3.で調べたDialectを派生(extends)させること。
「bitwise_and」というユーザ関数を追加しているわけです。

2つ目のクラスは、「BitwiseAndFunction.java」。

package パッケージ名;

import java.util.List;

import org.hibernate.QueryException;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.type.Type;

public class BitwiseAndFunction
    extends StandardSQLFunction implements SQLFunction {

    public BitwiseAndFunction(String name) {
        super(name);
    }

    public BitwiseAndFunction(String name, Type type) {
        super(name, type);
    }

    public String render(List args, SessionFactoryImplementor factory)
            throws QueryException {
        if (args.size() != 2) {
            throw new IllegalArgumentException("the function must be passed 2 arguments");
        }
        StringBuffer buffer = new StringBuffer(args.get(0).toString());
        buffer.append(" & ").append(args.get(1));  // ←ここにビット演算子を指定
        return buffer.toString();
    }
}

このクラスは、ユーザ関数「bitwise_and」の中身を受け持ちます。
ポイントは、returnする直前に指定しているビット演算子をデータベースに合わせること。今回は” & ”としてあります。

最後に、先程3.で調べるときに参照したHibernateコンフィグレーションファイルの、Dialectプロパティを、今作成したDialectクラスに書き換えればOKです。

実際の使い方ですが、例えばHQL上で

where bitwise_and( X, 1 ) = 1

のように書いてしまえばOKで、これで実際のSQL上は、

where X & 1 = 1

と送られることになります。

とりあえず僕はこれでうまくいきました。
参考にしたのは、以下のサイトです。
http://javabeans.asia/2008/05/06/bitwise_operation_in_hibernate_3.html

コメントを投稿

About

2010年05月17日 11:30に投稿されたエントリーのページです。

ひとつ前の投稿は「ますます快適になったN1ライフ」です。

次の投稿は「ドコモのSPモードを考える」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。