昨日はmrubyでMySQLのUDFを作ってみたんだけど、関数毎にCのプログラムを書くのがめんどくさいので、簡単なツールを作ってみた。
詳しくは 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 は特に無いんだよな…。