C#でFirebirdのストアドを書く
本エントリは、Firebird AdventCalender 2016 の14日目です。
今回は、Firebirdの.NET ProviderのコミッターであるJiri Cincura氏がブログで公開している、FbNetExternalEngineについて書きます。
目次
FbNetExternalEngineってなに?
簡単に言うと、C#でFirebirdのストアドがかけるようなpluginです。
Firebird3では新しいplugin機構が追加され、ストアドや関数、トリガー等がFirebirdの内部エンジン以外で動作できるようになりました。
基本的にはC++でpluginを書くことが想定されているようです。
そんな中Jiri Cincura氏が、C#用のplugin機構を仮実装したのが「FbNetExternalEngine」です。
ちなみに、procedureだけの対応です。
もっともお試し実装なので、Productionでは使えません。
簡単な例
実際にどんな風になるかというと。
こんなC#の関数を用意して、
public static IEnumerator<Tuple<string>> HellowWorld(string name) { yield return new Tuple<string>($"Hello World!!, Hello {name}!!"); }
SQL投げると、書いた処理が返ってくる。
実装
Firebird Embeddedで実際に試してみた。
検証環境
- C# (.NET 4.6.1)
- Firebird .NET Data Provider 5.6.0
- Firebird 3.0.0 (Embedded)
Firebirdのバージョンが古いですが、手元にあったのでそのままw
Pluginの作成
ポイントは以下の通り。
- static クラス
- static メソッド
- 戻り値はIEnumerator
IEnumerableではありません!私はよく間違えて動かない (゚A゚;)ってなってます。 - 引数は必ず用意する
引数無しだと上手く動かせなかった... - 引数/戻り値がPrimitive&Value Typeの場合死ぬので、Nullable
にする
こう見ると、割と制限が多い。
サンプル
namespace FbExternalSample { public static class Procedures { public static IEnumerator<Tuple<string>> HellowWorld(string name) { yield return new Tuple<string>($"Hello World!!, Hello {name}!!"); } public static IEnumerator<Tuple<int?>> GetNumbers(int? count) { return Enumerable.Range(0, count.Value).Select(x => Tuple.Create((int?)x)).GetEnumerator(); } public static IEnumerator<Tuple<int?, string>> GetDemo(string txt) { yield return new Tuple<int?, string>(1, "sample1"); yield return new Tuple<int?, string>(2, "sample2"); yield return new Tuple<int?, string>(3, $"{txt}"); yield return new Tuple<int?, string>(4, $"Done!!"); } } }
Pluginを呼ぶほう
まずは普通にEmbeddedが動く環境整備
適当に必要なDLLを配置する準備だけしておきます。
よくわからなければ、過去記事を参照。
Firebird3.0でEmbedded試してみた - ぽにょろん
FbNetExternalEngineを配置
下記ブログ記事から、必要なアセンブリを取得します。
External procedures in Firebird in .NET done(-ish) | tabs ↹ over ␣ ␣ ␣ spaces by Jiří {x2} Činčura
ちなみに、7zで圧縮されてます。解凍して、中身をpluginsフォルダに突っ込みます。
plugins.confの作成
Firebirdのplugin設定を変更するために、plugins.confを配置又は作成します。
中身はこんな感じで。
Plugin = FBNETEXTERNALENGINE { Module = $(dir_plugins)/FbNetExternalEnginePlugin Config = FBNETEXTERNALENGINE_config } Config = FBNETEXTERNALENGINE_config { }
DBにprocedure作成しておく
FirebirdのDBファイルを適当に作成して、そこにprocedureのcreate文を流し込みます。
recreate procedure HellowWorld (in_name varchar(300)) returns (out_0 varchar(300)) external name 'FbExternalSample!FbExternalSample.Procedures.HellowWorld' engine FbNetExternalEngine; recreate procedure GetNumbers (in_count integer) returns (out_0 integer) external name 'FbExternalSample!FbExternalSample.Procedures.GetNumbers' engine FbNetExternalEngine; recreate procedure GetDemo (in_txt varchar(300)) returns (out_0 integer,out_1 varchar(300)) external name 'FbExternalSample!FbExternalSample.Procedures.GetDemo' engine FbNetExternalEngine;
作成したPluginを配置する
上記で作成した、PluginのDLLもFirebirdのアセンブリがあるPluginsフォルダにぶち込みます。
実行
あとは、SQLを実行するだけ。
結構雑なコードですけど、こんな感じで確認すると、
var sqls = new[] { "SELECT * FROM HellowWorld('Taro')", "SELECT * FROM GetNumbers(5)", "SELECT * FROM GetDemo('やったぜ!')" }; using (var con = new FbConnection(builder.ConnectionString)) using (var command = con.CreateCommand()) { con.Open(); foreach (var sql in sqls) { Console.WriteLine("- SQL -"); Console.WriteLine(sql); Console.WriteLine("- 実行結果 -"); command.CommandText = sql; var reader = command.ExecuteReader(); while (reader.Read()) { var result = ""; for (var i = 0; i < reader.FieldCount; i++) { result += $" {reader[i]}"; } Console.WriteLine(result); } Console.WriteLine("------------------------------------"); } }
こんな結果になります。
最後に
Jiri Cincura氏のブログ読んで貰えればわかりますが、実際はまだまだ試作段階です。
制限も多いし手順も割と面倒ではありますが、まぁ、とりあえずできるよ!という状況です。
とはいえ、どれくらい存在するのかわからない、Firebird + C#erには嬉しいので、色々と試してみてはいかがでしょうか。
記事を書くのに殴り書いたサンプルも置いておきます。
Sample/FbExternalSample at master · kowill/Sample · GitHub
HTML5 CONFERENCE 2016 に参加してきた
HTML5 CONFERENCE 2016 に参加してきました。
参加時と後から録画をちらっと見たメモを記載しておきます。
公式HP
events.html5j.org
YouTube - ライブ配信録画 www.youtube.com
目次
- 目次
- 基調講演
- ブラウザ用のCPUをつくるよ!WebAssemblyで
- Webのグラフィックス前編: WebGL事例、パフォーマンス
- Webのグラフィックス後編: WebGL2、そしてWebVR
- Webパフォーマンス最前線
- 最後に
基調講演
中村さん
- Webという名の Distributed Operating System
- インターネットで世界中のコンピュータが繋がってる
- Webページは世界中のドキュメント
- みんなで分散システムを作ってるみたいなもん
- Block Chain に関するワークショップ
分散システムにおけるTrustをどうやって作るか
参加者の合意でTrust作れるんじゃないの?という可能性
及川さん
- 実はIE7担当してました
- HTML5というキーワードはもういいんじゃないの? → Webそのもの
- モバイルWebはUI/UXが悪いことが多くなってきた
キュレーションアプリとかが流行ってきた理由の一つでもある - ProgressiveWebApp
よりアプリ化されたWeb - モバイルWebの課題対応について
Accelerated Mobile Pages - Webは何度も死んでるw
が、生き返る
medium.com
ブラウザ用のCPUをつくるよ!WebAssemblyで
- WebAssemlby は WASM VM上で動くよ
- WebAssembly の Working Grop Mozzila, Microsoft, Google, Apple の各社から人が来てる
- asm.js と比較すると WebAssembly の方が Binary Size が小さい
- WASM はコンパイルの生成物
Nativeではなく、parsingが終わってるだけ。
ASTのバイト表現。 - まだまだこれからの技術
Webのグラフィックス前編: WebGL事例、パフォーマンス
Webのグラフィックス2016
- WebGLを実務で使ってる人 → 昨年より増えている感じ。(参加者の)
- 3D、難しい、大規模コンテンツ というイメージが強い 2Dでも使えるし、Three.js等を使うことで、割と簡単にできる
- 表現を広げる選択肢になるうる
- 小さいコンテンツから始めると良い
ものによってはCSS等で頑張るよりも、簡単なケースもある
資料
WebGL最適化の勘所
- GPU処理のおさらい
- ボトルネックになりやすい場所
JS & WebGLドライバ パフォーマンスチェックして最適化しよう - まずはCPUボトルネックを疑おう Windows版のChrome等では、WebGL実装がDirectXに命令に変換してたりするのもある
- WebGLプロファイラ
- WebGL専用ではないけど、おすすめ
tracing-framework by Google - プロファイラ使ってるときは、とうぜんその負荷もプラスされるので、相対値で考える
- WebGL専用ではないけど、おすすめ
- WebGL独自のTips
gl.TRIANGLE_FANは避ける
頂点アトリビュートは4byte境界に揃える
etc... - ライブラリ使ってるときは?
WebGL命令が隠蔽される とにかくドキュメント読め!
stackoverflowとかでノウハウ集めよう → 有名なライブラリ使ったほうが楽
資料
WebGL最適化の勘所
Webのグラフィックス後編: WebGL2、そしてWebVR
WebGL 2.0
- 1.0と比較して、劇的進化しているわけではない
普段から WebGL をぺろぺろしてないと、そこまで恩恵はないかも - WebGL 2.0 がきたら
- より 美しく現実的/高速で効率的 なレンダリングができる
- リソースやデータ方が柔軟になる
- テクスチャの画像データサイズが2の累乗でなくてもよくなる
- 既存のコンテンツはそのままでも大丈夫 実装が別
- 学習が難しくなるか?
そもそも3DCG全般ムツカシイ
日本語情報はほぼない
そしてWebVR
資料
Webパフォーマンス最前線
- Webがアプリのように振る舞うことが求められている
Progressive Web Apps - パフォーマンスに対する優先度
- Webサイト
LoadやAnimationが重要 - Progressive Web Apps
ResponseやAnimationが重要
- Webサイト
- GPUを活用しよう
ex) translate, will-change -> 常時使うと電池とかに悪影響なので、上手く使おう - 通信量を気にするところから、UIを早くしようという方向にきてる
最後に
所用で最後までは参加せずに帰ったのですが、とても勉強になりました。
率直に思ったのは以下の通り。
かなりのバイアスがかかってるけど、Web周りの話を聞きに行ったのに、スタックマシンやAST、GPUの話を聞いたイメージばかりが残ってる。
— kowill (@kowillm) 2016年9月3日
WebページがどんどんNativeっぽくなってる側面は確かにあるなぁというのが実感。
あと、俺、Webの知識が足りないなぁ。というのも。頑張ります。
FAManagementStudioなるものを作ってます
以前からFirebird Embedded用のGUIツールを作成、公開しています。
名前は「FAManagementStudio」です。
その宣伝記事になります。
目次
背景
Firebird Embeddedを以前から使っていたのですが、個人的に使い勝手の良いGUIツールにめぐり合わなかったので、簡易なものを作ってみました。というのが背景です。
定番ツールのFlameRobinも悪くないのですが、ちょっと馴染めなかった。
ちなみにWindows環境のみ対応。
Firebird2.5/3の両方で使用可。
ツールの概要
とにかくお手軽に使えるようにという方針です。
DBファイルをドロップ、SQLを実行(F5)、結果を確認するといったイメージです。
詳しい使い方
GithubのWikiを少しづつメンテしているので、そちらを参照ください。*1
Home · degarashi0913/FAManagementStudio Wiki · GitHub
開発環境
VS2015 + C# + WPF です。
Ver1の時は.NET3.5で作成していましたが、Ver2で.NET4.5に変更しました。
最後に
Firebird Embeddedを使っている方がいれば、ぜひ一度試してみてください。
まだまだ機能が足りなかったり、バギーだったりしますがその際はFB、PRお待ちしております。
*1:主に他のメンバーが
WPFでRadioButtonにEnumをBindする
目次
環境
実現したいこと
RadioButtonにViewModelのプロパティ値(Enum)をBindする。
実装の方針
- 各RadioButtonのIsCheckedにEmun値をバインドさせる。
- Converterを用意して、Bool値に変換する。
実装
Converter
検索すると色々な方法があるみたいですが、簡単にこんな感じで作ってみました。
[ValueConversion(typeof(Enum), typeof(bool))] public class RadioButtonConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null || parameter == null) return false; return value.ToString() == parameter.ToString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null || parameter == null) return Binding.DoNothing; if ((bool)value) { return Enum.Parse(targetType, parameter.ToString()); } return Binding.DoNothing; } }
Bindingしない時は Binding.DoNothing を使うようです。
Binding.DoNothing フィールド (System.Windows.Data)
VMとEnum
public class ViewModel { public TestEnum TestKind { get; set; } = TestEnum.Test4; } public enum TestEnum { Test1, Test2, Test3, Test4 }
View
RadioButtonはGroupNameを付けておく。
ConverterParameterを指定する。
<Window x:Class="WpfRadioButtonSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfRadioButtonSample" mc:Ignorable="d" Title="MainWindow" Height="100" Width="100"> <Window.Resources> <local:RadioButtonConverter x:Key="EnumConverter" /> </Window.Resources> <StackPanel> <RadioButton GroupName="Test" Content="Test1" IsChecked="{Binding TestKind, ConverterParameter=Test1, Converter={StaticResource EnumConverter}}"/> <RadioButton GroupName="Test" Content="Test2" IsChecked="{Binding TestKind, ConverterParameter=Test2, Converter={StaticResource EnumConverter}}"/> <RadioButton GroupName="Test" Content="Test3" IsChecked="{Binding TestKind, ConverterParameter=Test3, Converter={StaticResource EnumConverter}}"/> <RadioButton GroupName="Test" Content="Test4" IsChecked="{Binding TestKind, ConverterParameter=Test4, Converter={StaticResource EnumConverter}}"/> </StackPanel> </Window>
ちょっとばかし嵌ってしまったので、メモ。
Firebird .NETProviderで実行計画を取得する
目次
環境
実装
FBCommandクラスにCommandPlanメソッドがあるので、それを呼び出すだけです。
using (var con = new FbConnection("接続文字列")) using (var command = con.CreateCommand()) { con.Open(); command.CommandText = @"select * from rdb$indices where rdb$system_flag = 0"; command.ExecuteReader(); Console.WriteLine(command.CommandPlan); }
このメソッド、Browsable属性がfalseですが、特に問題ないでしょう。
いわゆる、Isqlでいう set plan on; の状態なので、SQLを実行しないと実行計画を取得できません。
実行計画の見方
他のDBMSの実行計画と比べると、Firebirdは少し特徴的に見えますが、そういう時は
Referenceを参照しましょう。
ちゃんとDocumentが用意されてます。