同一プログラムからFirebird2.5と3.0のDBにアクセスしたい
同一プログラムからFB3とFB2.5にアクセスするシナリオを考え、サンプルを作ってみました。
目次
環境
課題
- DBにアクセスする前に、ファイルのODSバージョンを知りたい
- FB2.5とFB3.0のDLLの共存
ODSバージョンの取得
Firebirdのデータベースファイルは一つのバイナリです。
ググった結果、このバイナリを読んで、ヘッダーページにアクセスすれば良さそうということが分かりました。
データベースファイルの内部構造を探ってみた(2/3) − @IT
ただ、情報が古そうなのでソースコードを探してみることに。
atmarkitの記事と相違はありそうですが、大体よさそう。
ということで、2パターン試してみた。
structを使うパターン
定義を写経して、
[StructLayout(LayoutKind.Sequential)] public struct HeaderPage { public Pag hdr_header; // Page size of database [MarshalAs(UnmanagedType.U2)] public ushort hdr_page_size; // Version of on-disk structure [MarshalAs(UnmanagedType.U2)] public ushort hdr_ods_version; // Page number of PAGES relation [MarshalAs(UnmanagedType.U4)] public uint hdr_PAGES; // Page number of next hdr page [MarshalAs(UnmanagedType.U4)] public uint hdr_next_page; ....
Marshalのメソッドをつくり、
public static T RawDataToObject<T>(byte[] rawData) where T : struct { var pinnedData = GCHandle.Alloc(rawData, GCHandleType.Pinned); try { return (T)Marshal.PtrToStructure(pinnedData.AddrOfPinnedObject(), typeof(T)); } finally { pinnedData.Free(); } }
ファイル読んで、完成。
private const ushort FirebirdFlag = 0x8000; .... using (FileStream stream = new FileStream(path, FileMode.Open)) { var buf = new byte[1024]; stream.Read(buf, 0, buf.Length); var header = RawDataToObject<HeaderPage>(buf); var odsVersion = header.hdr_ods_version & ~FirebirdFlag; Console.WriteLine($"ODSVer: {odsVersion}"); Console.WriteLine($"ODSMinorVer: {header.hdr_ods_minor}"); }
必要なところだけ変換
private const ushort FirebirdFlag = 0x8000; .... using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { int fileSize = (int)fs.Length; byte[] buf = new byte[1024]; fs.Read(buf, 0, 1024); var obsHex = buf.Skip(0x12).Take(2).Select(x => x.ToString("X2")).Reverse().Aggregate("", (x, y) => x + y); var minor = buf.Skip(0x40).Take(2).Select(x => x.ToString("X2")).Reverse().Aggregate("", (x, y) => x + y); Console.WriteLine($"ODSVer: {Convert.ToInt32(obsHex, 16) & ~FirebirdFlag}"); Console.WriteLine($"ODSMinorVer: {Convert.ToInt32(minor, 16)}"); }
比較
どちらでも行けますが、個人的にはstructでMarshallする方がよいのではと思ってます。*1
結局、定義とにらめっこしたり、リトルエンディアンの処理する必要がありますし。
注意点として、OdsVersionはそのままの値ではだめで、0x8000とのANDをとってあげる必要があります。
firebird/pag.cpp at B3_0_Release · FirebirdSQL/firebird · GitHub
※バイナリ眺めてるときにちゃんとやるなら上記みたいにやらないとだめだけど、
ODSも2桁だし、ODS_MINORも1桁だし普通にリトルエンディアンとか放置でも行けるじゃんって思いました。
FB3とFB2.5の共存
まず必要なDLLをプロジェクトに突っ込んでおきます。
あとは、FBConnectionのClientLibraryに使いたい方のDLLを指定してあげるだけ。
var builder = new FbConnectionStringBuilder(); builder.DataSource = "localhost"; builder.Database = @"D:\DB\TESTFB3.FDB"; builder.ServerType = FbServerType.Embedded; builder.ClientLibrary = @"dll\fb3\fbclient"; ....
var builder = new FbConnectionStringBuilder(); builder.DataSource = "localhost"; builder.Database = @"D:\DB\TESTFB2.FDB"; builder.ServerType = FbServerType.Embedded; builder.ClientLibrary = @"dll\fb25\fbembed"; ....
こうすれば特に問題なく共存が可能です。
Process.GetCurrentProcess().Modules で見てみるとこんな感じになります。
解決
これで課題は解決できたので、あとは必要に応じて処理を組み込めば、同一プログラムからの呼び出しは問題なしです。
与えられたDBファイルから判断して、処理を変えることも可能です。
実際に自分のプロジェクトでやろうとしていたんですが、諸事情でサスペンドしてますw
本当に問題がないのかは不明ですが、今回はこんな感じで終了です。
一応、サンプルを。
*1:使い方大丈夫なのだろうか
C#+FirebirdでExeの終了が遅かった件がFB3では再現しなくなっていた
以前記事にした以下の件、Firebird3.0で置き換え試したところ、
再現しなくなっていました。
Firebird2.5特有の問題なのか、Firebird3.0での修正に伴い解消されたのか。
謎ですが、一安心。
Firebird3.0でEmbedded試してみた
昨日(4月19日)、Firebird3.0(以下FB3)が正式にReleaseされました。
せっかくなので、FB3でのEmbedded接続を試してみました。
C#です。
目次
今回試した環境
FB2.5からの大きな変更点
これまでWindows版ではEmbedded用のパッケージが別に用意されていましたが、
FB3からは一緒になったようです。
キムラデービーブログさんに詳しくあるので、そちらを参照してください。
Firebirdのバイナリを取得
www.firebirdsql.org
上記から、目的のプラットフォームに合わせて取得。
必要なDLLをコピー
今回必要なものを以下の2つ。
* fbclient.dll
* plugins/engine12.dll
最終的に、以下のようなフォルダ階層になればOK。
ソースコード
プロジェクトのプラットフォームターゲットの変更に注意。
x86バイナリなら、x86に。x64ならそのように。
実行結果
rank や boolean型を使えていることが確認できます。
Hello Firebird 3.0!完了!
注意事項
.NET Data Provider
2016/4/20時点でNugetから取得した、FirebirdSql.Data.FirebirdClientは
FB3から対応したBoolean型の型変換できずエラーになります。
Window関数やその他DBの機能に関してはほとんど動きそうですが、
Boolean型を試したい場合は、素直にCloneして自前で構築しましょう。*1Firebird2.5で作成したDBについて
ODS(On-Disk Structure)が変更になっているため、上記の手順で参照するとエラーになります。
マイグレーションする必要があるようです。
ツールとかで両バージョン参照したいとかは一工夫(?)いりそうですね。。サポートライブラリ
上記手順では、サポートライブラリ*2入れてませんが、
入れておかないと、firebird.logに読み込み失敗ログが出ます。
ちゃんとした環境で使うときは入れて下さい。
Firebirdのシステムデータにアクセスしたい場合
DBを扱うプログラムを書く際に、テーブルやカラム、インデックスやトリガー等の一覧を取得したい場合がありませんか?
何かと検索しているので、Firebirdの場合をメモしておきます。
目次
環境
Firebird Embedded 2.5.4
FirebirdSql.Data.FirebirdClient 4.10.0.0
C#
.NET Provider使う場合
FirebirdSql.Data.FirebirdClient使える場合は、非常に簡単です。
GetSchemaしましょう。
テーブル一覧が必要であれば、
using (var con = new FbConnection(接続文字列)) using (var command = con.CreateCommand()) { con.Open(); con.GetSchema("Tables"); }
とすれば、
みたいに取れます。
引数を追加してあげれば、
con.GetSchema("Tables", new[] { null, null, null, "TABLE" });
ユーザーテーブル一覧を取得できます。
制限しない場合は、System Tables(RDB$xxx)とかMonitoring Tables(MON$xxx)とかViewとかもれなくついてきます。
各スキーマの引数一覧
そんな便利なものは見つけてません。(ノ゚ω゚)ノ*
あきらめてソースコードから引っ張りましょう。
大抵のケースで、
* restrictions [0] : TABLE_CATALOG
* restrictions [1] : TABLE_SCHEMA
* restrictions [2] : TABLE_NAME
* それ以降、個別
となっているっぽいです。
(※上記、new[] { null, null, null, "TABLE" }の部分。)
SQLを自力で書く場合
Referenceとにらめっこしましょう。
.NET Providerのソースコードから、必要なSQLの参考にするのもありかなと思います。
テーブル一覧
select rdb$relation_name AS Name from rdb$relations where rdb$relation_type = 0 and rdb$system_flag = 0 order by rdb$relation_name asc
列の一覧取る際に、型名,PK,FK等の付属情報つけようとすると、SQLが複雑になって、めんどかったです。
ほかのRDBも似たような感じなんだろうか。。
Nano Server 試してみた。(Windows Server 2016 TP4)
以前からちょこちょこっと試してはいたのですが、先日のComCampで刺激を受けたこともあり、手順を残しておきます。
目次
NanoServerとは
「プライベートクラウドやデータセンターでホストするのに最適化された、リモート管理OS」らしいです。
Getting Started with Nano Server
個人的な目的
「簡単に立てたり捨てたりできる、軽いIISをHyper-Vに乗っけたい」というのが動機だったりします。
事前準備
Windows Server 2016 Technical Preview 4 のISOを取得してきます。
ちなみにEnglish版です。
Japanese版でもやってみたんですが、文字化けしました。
フォントなのか、なんなのか。
ISOをマウントして、必要なファイルを適当なフォルダに突っ込んでおきます。
unatteend.xmlはISOにないので、こちらは必要に応じて事前に適当に作っておきます。
作成
やることは、以下のような内容です。
1. Hyper-Vの仮想マシン用にNanoServerのWIMをVHDXに変換。
2. DISMでVHDXをカスタマイズ。
3. Hyper-Vに仮想マシン作成して、そこへVHDXを追加。
下記のようなスクリプトを管理者権限で実行して、
仮想マシン立ち上げると下記のような感じになると。
上記の例だとIISのPackage入れてなかったりしますが、目的は一応達成。
困ったこと
きちんと理解してないのが原因ですが、dismなのかPowerShellなのか構築スクリプトがたまにエラーで落ちます。
あれこれしているうちに解決してしまうので、深追いしてません。(すいません
まだ、Technical Previewなので色々変わる可能性もありますが、とりあえずやってみたという感じです。
以下のサイトを参考にさせていただいたので、試す方はそちらをどうぞ。
山市良のえぬなんとかわーるど: 山市良版 Getting Started with Nano Server
それと公式ページも。