mrubyudf : C を書かずに Ruby だけで MySQL の UDF を作る

昨日はmrubyでMySQLのUDFを作ってみたんだけど、関数毎にCのプログラムを書くのがめんどくさいので、簡単なツールを作ってみた。

github.com

詳しくは README 参照。

fib.rb と fib.spec をこんな感じで作っておいて、

fib.rb

LONG_LONG_MAX = 9223372036854775807

def fib(n)
  b = 1
  c = 0
  n.times do
    a, b = b, c
    c = a + b
    raise 'Overflow' if c > LONG_LONG_MAX
  end
  c
end

fib.spec

MrubyUdf.function do |f|
  f.name = 'fib'           # 関数名は fib
  f.return_type = Integer  # 戻り値は Integer
  f.arguments = [          # 引数は一つで型は Integer
    Integer
  ]
end
% mrubyudf fib.spec

とやれば fib.so が出来上がるはず。 コンパイルオプションとかは自分の環境決め打ちなのでうまくいかないかもしれない。

% sudo cp fib.so $(mysql_config --plugindir)
% mysql -uroot
mysql> create function fib returns int soname 'fib.so';
mysql> select fib(10);
+---------+
| fib(10) |
+---------+
|      55 |
+---------+

ところで、mruby のインスタンスは関数を使うクエリが発行されたタイミングで生成されて、クエリ終了時に破棄される。

つまり、クエリの実行中はグローバル変数が生存しているので、こんな感じにすると、

rownum.rb

$n = 0
def rownum()
  $n += 1
end

rownum.spec

MrubyUdf.function do |f|
  f.name = 'rownum'
  f.return_type = Integer
  f.arguments = []
end

クエリ結果に行番号をつけることができたりもする。面白いかも。

mysql> create function rownum returns int soname 'rownum.so';
mysql> select rownum(),character_set_name from information_schema.character_sets;
+----------+--------------------+
| rownum() | CHARACTER_SET_NAME |
+----------+--------------------+
|        1 | big5               |
|        2 | dec8               |
|        3 | cp850              |
|        4 | hp8                |
|        5 | koi8r              |
|        6 | latin1             |
|        7 | latin2             |
|        8 | swe7               |
|        9 | ascii              |
|       10 | ujis               |
|       11 | sjis               |
|       12 | hebrew             |
|       13 | tis620             |
|       14 | euckr              |
|       15 | koi8u              |
|       16 | gb2312             |
|       17 | greek              |
|       18 | cp1250             |
|       19 | gbk                |
|       20 | latin5             |
|       21 | armscii8           |
|       22 | utf8               |
|       23 | ucs2               |
|       24 | cp866              |
|       25 | keybcs2            |
|       26 | macce              |
|       27 | macroman           |
|       28 | cp852              |
|       29 | latin7             |
|       30 | cp1251             |
|       31 | utf16              |
|       32 | utf16le            |
|       33 | cp1256             |
|       34 | cp1257             |
|       35 | utf32              |
|       36 | binary             |
|       37 | geostd8            |
|       38 | cp932              |
|       39 | eucjpms            |
|       40 | gb18030            |
|       41 | utf8mb4            |
+----------+--------------------+

しかし、ツールを作ってはみたものの別に作りたい UDF は特に無いんだよな…。