MySQLのUDFをGoで書く

前回、Go1.5を使ってC共有ライブラリを生成しました。

この時は、単純にsoをビルドしてpythonのREPLからエクスポートされた関数が実行できるかを見たのですが、このテクノロジーを使ってMySQLのUDFをGoで書いてみたのが今回です。 環境は、以下です。

$ cat /etc/redhat-release 
CentOS release 6.6 (Final)
$ go version
go version go1.5 linux/amd64
$ mysql
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.1.73    |
+-----------+
1 row in set (0.00 sec)

コードは、以下です。 github.com



まずは、ビルドします。

$ go build -buildmode=c-shared -o main.so main.go

次に、生成されたライブラリを、mysqlプラグイン配置先にコピーします。

$ sudo cp -p main.so  /usr/lib64/mysql/plugin/

あとは、mysqlCLIからUDFを定義し、実行します。 いろいろ考慮は足りていないとは思いますが、OSのシェルコマンドを文字列として渡せば実行結果が返ってくる的なものになっています。

mysql> create function myexec returns string soname 'main.so';
Query OK, 0 rows affected (0.00 sec)

mysql> select myexec("hostname");
+---------------------------------+
| myexec("hostname")              |
+---------------------------------+
| vagrant-centos66.vagrantup.com
 |
+---------------------------------+
1 row in set (0.01 sec)


書いてみてですが、Goで書けるようになったこと自体は面白くて、いろいろ妄想が膨らみますが、 以下のように、cgoで頑張って型変換をこねくり回しているので、煩雑という感じが。。。

//export myexec
func myexec (initid *C.UDF_INIT, args *C.UDF_ARGS, result *C.char, length *C.ulong, is_null *C.char, error *C.char) *C.char { 
  out, err := exec.Command(C.GoString(*args.args)).Output()
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  result = C.CString(string(out))
  *length = C.ulong(utf8.RuneCountInString(C.GoString(result)))
  return result
}

前回のように、ここにさらにmrubyまで導入して、 CとGoとmrubyでUDFを書くこともやってみたいけど更に複雑化するだけかも。。