db4o その19(StoredField#get()のbug)
先日のエントリでは、db4oにおけるフィールドの型が変更された場合の振舞いと、データベースに格納されているオブジェクトのデータからメタデータを抽出する方法について言及したが、StoredField#getメソッドを使用してデータベースに格納されているオブジェクトの任意のフィールド値を取得しようとしても上手く行かないことが解った。
ObjectContainer oldDb = Db4o.openFile("roster.db"); StoredClass sc = oldDb.ext().storedClass("PlayerImpl"); StoredField oldField = sc.storedField("position", String.class); String playerName = "D.Jeter"; ObjectSet resultSet = sodaForPlayer(olddb, playerName); IPlayer jeter = (IPlayer)playerName.next(); System.out.println(playerName + " position? = " + oldField.get(jeter));
ちなみに、サンプルで通して使用しているdb4oのバージョンは最新開発版のver6.2.501である。(このバージョンを使わないとCachedIoAdapterやObjectContainer#backupでバグが発生する)
さて、この不具合?だがやはり既知のバグのようだ。同様のトラブルが既にdb4o UserForumでポストされているのを見つけた。
既にBTS上でオープンになっているので修正されるのは時間の問題だろう。
Field type refactoring runs into null reference
また、このポストにはディスクリプションが書き込まれており、修正することで取りあえずバグを回避できるらしいと書いてある。
seems to run into a null reference for the "sfOld.get(pilot)" call, as it ends up in FieldMetadata#read() where it is classified as !active(). Simply removing this check seems to fix the symptom, however, it is likely there for a (performance) reason. Probably needs a closer look.
実際にFieldMetadata.javaの同readメソッドを見てみた。文中のactive()メソッドはalive()のタイポだと思われるが、確かにここの判定を省くと予想通りの結果を返すことは確認できた。
Object read(MarshallerFamily mf, StatefulBuffer a_bytes) throws CorruptionException, IOException {
/*
if (!alive()) {
incrementOffset(a_bytes);
return null;
}
*/
return i_handler.read(mf, a_bytes, true);
}
まあしかし、大人しく次の版を待ったほうが良さそうではある。
- 閑話休題
db4oに限ったことではないがオープンソースなDBMSって素晴らしいなと。DBMSこそオープンにすべき分野だろうと感じる。今回のようなバグが発覚したとして、プロプライエタリなデータベースの場合はまずすぐにfixされることはまず無いだろう。
また、プロプライエタリなDBMSはベンダのサポートがあるのが安心だとか、オープンソースだからバグが多いのではないか、品質ならば有名ベンダが安心だとかいう話を未だに聞くのは何故だろう。
サポートはともかく、DBMSに限らずプロプライエタリなほうがコードの品質が良いというのは全く当てにならないと思うがなぁ。