ぽにょろん

思いついたこととメモ

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では使えません。

Early (very) preview of stored procedures (functions, triggers) in .NET in Firebird | tabs ↹ over ␣ ␣ ␣ spaces by Jiří {x2} Činčura

簡単な例

実際にどんな風になるかというと。
こんなC#の関数を用意して、

public static IEnumerator<Tuple<string>> HellowWorld(string name)
{
    yield return new Tuple<string>($"Hello World!!, Hello {name}!!");
}

SQL投げると、書いた処理が返ってくる。

f:id:kowill:20161211015954p:plain

実装

Firebird Embeddedで実際に試してみた。

検証環境

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を配置する準備だけしておきます。
f:id:kowill:20161211015957p:plain
よくわからなければ、過去記事を参照。

Firebird3.0でEmbedded試してみた - ぽにょろん

FbNetExternalEngineを配置

下記ブログ記事から、必要なアセンブリを取得します。

External procedures in Firebird in .NET done(-ish) | tabs ↹ over ␣ ␣ ␣ spaces by Jiří {x2} Činčura

ちなみに、7zで圧縮されてます。解凍して、中身をpluginsフォルダに突っ込みます。 f:id:kowill:20161211015959p:plain

plugins.confの作成

Firebirdのplugin設定を変更するために、plugins.confを配置又は作成します。 f:id:kowill:20161211020001p:plain
中身はこんな感じで。

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フォルダにぶち込みます。
f:id:kowill:20161211021008p:plain

実行

あとは、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("------------------------------------");
    }
}

こんな結果になります。
f:id:kowill:20161211021715p:plain

最後に

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

目次

基調講演

中村さん

  • 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のバイト表現。
  • まだまだこれからの技術

資料
speakerdeck.com

Webのグラフィックス前編: WebGL事例、パフォーマンス

Webのグラフィックス2016

  • WebGLを実務で使ってる人 → 昨年より増えている感じ。(参加者の)
  • 3D、難しい、大規模コンテンツ というイメージが強い 2Dでも使えるし、Three.js等を使うことで、割と簡単にできる
  • 表現を広げる選択肢になるうる
  • 小さいコンテンツから始めると良い
    ものによってはCSS等で頑張るよりも、簡単なケースもある

資料

www.slideshare.net

WebGL最適化の勘所

  • GPU処理のおさらい
  • ボトルネックになりやすい場所
    JS & WebGLドライバ パフォーマンスチェックして最適化しよう
  • まずはCPUボトルネックを疑おう Windows版のChrome等では、WebGL実装がDirectXに命令に変換してたりするのもある
  • WebGLプロファイラ
    • WebGL専用ではないけど、おすすめ
      tracing-framework by Google
    • プロファイラ使ってるときは、とうぜんその負荷もプラスされるので、相対値で考える
  • WebGL独自のTips
    gl.TRIANGLE_FANは避ける
    頂点アトリビュートは4byte境界に揃える
    etc...
  • ライブラリ使ってるときは?
    WebGL命令が隠蔽される とにかくドキュメント読め!
    stackoverflowとかでノウハウ集めよう → 有名なライブラリ使ったほうが楽

資料
WebGL最適化の勘所

Webのグラフィックス後編: WebGL2、そしてWebVR

WebGL 2.0

  • 1.0と比較して、劇的進化しているわけではない
    普段から WebGL をぺろぺろしてないと、そこまで恩恵はないかも
  • WebGL 2.0 がきたら
    • より 美しく現実的/高速で効率的 なレンダリングができる
    • リソースやデータ方が柔軟になる
    • テクスチャの画像データサイズが2の累乗でなくてもよくなる
  • 既存のコンテンツはそのままでも大丈夫 実装が別
  • 学習が難しくなるか?
    そもそも3DCG全般ムツカシイ
    日本語情報はほぼない

資料
WebGL 2.0 現実的な影響は?

そしてWebVR

  • WebVRとは
    VR体験のためのデバイスやセンサーから情報取得するAPIのこと
    → 3Dのコンテンツ部分はWebGLで作る
  • まだサポートブラウザがほぼない
    これからの技術

資料

www.slideshare.net

Webパフォーマンス最前線

  • Webがアプリのように振る舞うことが求められている
    Progressive Web Apps
  • パフォーマンスに対する優先度
    • Webサイト
      LoadやAnimationが重要
    • Progressive Web Apps
      ResponseやAnimationが重要
  • GPUを活用しよう
    ex) translate, will-change -> 常時使うと電池とかに悪影響なので、上手く使おう
  • 通信量を気にするところから、UIを早くしようという方向にきてる

最後に

所用で最後までは参加せずに帰ったのですが、とても勉強になりました。
率直に思ったのは以下の通り。

WebページがどんどんNativeっぽくなってる側面は確かにあるなぁというのが実感。
あと、俺、Webの知識が足りないなぁ。というのも。頑張ります。

FAManagementStudioなるものを作ってます

以前からFirebird Embedded用のGUIツールを作成、公開しています。
名前は「FAManagementStudio」です。

github.com

その宣伝記事になります。

目次

背景

Firebird Embeddedを以前から使っていたのですが、個人的に使い勝手の良いGUIツールにめぐり合わなかったので、簡易なものを作ってみました。というのが背景です。
定番ツールのFlameRobinも悪くないのですが、ちょっと馴染めなかった。
ちなみにWindows環境のみ対応。
Firebird2.5/3の両方で使用可。

ツールの概要

とにかくお手軽に使えるようにという方針です。
DBファイルをドロップ、SQLを実行(F5)、結果を確認するといったイメージです。 f:id:kowill:20160804221908p:plain

詳しい使い方

GithubWikiを少しづつメンテしているので、そちらを参照ください。*1

Home · degarashi0913/FAManagementStudio Wiki · GitHub

開発環境

VS2015 + C# + WPF です。
Ver1の時は.NET3.5で作成していましたが、Ver2で.NET4.5に変更しました。

最後に

Firebird Embeddedを使っている方がいれば、ぜひ一度試してみてください。
まだまだ機能が足りなかったり、バギーだったりしますがその際はFB、PRお待ちしております。

*1:主に他のメンバーが

WPFでRadioButtonにEnumをBindする

目次

環境

  • C# + WPF
  • .NET Framwork4.5.2

実現したいこと

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)

VMEnum

VMEnumの定義は適当に。

    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が用意されてます。

github.com