MySQL道普請便り

第70回 UDFを動かしてみよう

この記事を読むのに必要な時間:およそ 2.5 分

今回は,MySQLを拡張するための仕組み「UDF(User Defined Function)⁠を作ってみたいと思います。UDFは,文字通りユーザが自由にMySQLに関数を追加するための仕組みになっています。

そこで,今回はMySQLのソースコードにバンドルされているコードを例に,CentOSでのコンパイルの方法やUDFの使い方を説明していきたいと思います。

検証環境

第10回 yum, rpmインストールにおけるMySQL 5.6とMySQL 5.7の違いで紹介された,yumリポジトリを使用したインストールを利用しています。また,MySQLのバージョンは5.7.22を使用しています。つい先日(2018年4月19日)にMySQL 8.0もGAになりましたが,今回は5.7を利用していきます。

また今回はCentOS 7.4上で確認を行っています。

MySQLのソースコードをダウンロードする

今回はyumでインストールしたMySQLを利用する予定ですが,コンパイルするUDFはMySQLのソースコードに入っているものを使います。そのため,まずはじめにMySQLのソースコードをダウンロードします。

今回はwgetを使って以下のようにダウンロードしました。

$ wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.22.tar.gz
$ ls
mysql-5.7.22.tar.gz

ダウンロードしたmysql-5.7.22.tar.gzファイルをtarコマンドを使って展開します。

$ tar xzvf mysql-5.7.22.tar.gz
$ ls
mysql-5.7.22  mysql-5.7.22.tar.gz

mysql-5.7.22というディレクトリに展開されたことがわかります。

コンパイルをしてみる

それでは,コンパイルをしてみましょう。今回はコンパイルをする際にmysql_configを利用します。

mysql_configを使う

mysql_configはクライアントをコンパイルするためのコマンドです。今回は,作成するUDFを今あるクライアントの設定と揃えるために利用します。mysql_configコマンドを何もオプションを付けずに実行をすると,オプションの一覧とそれに対応したオプションが表示されます。

# mysql_config
Usage: /usr/bin/mysql_config-64 [OPTIONS]
Compiler: GNU 4.8.5
Options:
        --cflags         [-I/usr/include/mysql -m64 ]
        --cxxflags       [-I/usr/include/mysql -m64 ]
        --include        [-I/usr/include/mysql]
        --libs           [-L/usr/lib64/mysql -lmysqlclient -lpthread -lm -lrt -ldl]
        --libs_r         [-L/usr/lib64/mysql -lmysqlclient -lpthread -lm -lrt -ldl]
        --plugindir      [/usr/lib64/mysql/plugin]
        --socket         [/var/lib/mysql/mysql.sock]
        --port           [0]
        --version        [5.7.22]
        --libmysqld-libs [-L/usr/lib64/mysql -lmysqld -lpthread -lm -lrt -lcrypt -ldl -laio -lnuma]
        --variable=VAR   VAR is one of:
                pkgincludedir [/usr/include/mysql]
                pkglibdir     [/usr/lib64/mysql]
                plugindir     [/usr/lib64/mysql/plugin]

たとえば,今回利用する--cflagsオプションを付けた場合,右の-I/usr/include/mysql -m64という文字列が出力されます。

$ mysql_config --cflags
-I/usr/include/mysql -m64

直接文字列を打ち込むのではなく,このコマンドを利用することによって,環境の違いなどを吸収することができるようになります。ただし,このコマンドはシェルスクリプトで実装されているため,シェルが実行できる環境に無いと利用できないことに注意してください。

また,mysql_configが見つからないというエラーが出る場合がありますが,その場合はsudo yum install mysql-community-develを行ってMySQLの開発用のヘッダやツールをインストールしましょう。

UDFをコンパイルする

さて話を戻しまして,ダウンロードしたソースコードの中には,UDF用の例としてudf_example.ccというソースコードがmysql-5.7.22/sqlディレクトリに用意されています。こちらを前述のmysql_configと組み合わせて行います。とりあえず,sqlディレクトリに移動をしてファイルを確認してみましょう。

$ cd mysql-5.7.22/sql
$ ls | grep udf
locking_service_udf.cc
sql_udf.cc
sql_udf.h
udf_example.cc
udf_example.def

今回利用したいudf_example.ccがいることが確認できます。続いてコンパイルを行います。

$  gcc  -o udf_example.so udf_example.cc `mysql_config --cflags` -shared -fPIC

ここで利用している-sharedオプションと-fPICオプションは,共有ライブラリを作る時に使うオプションです。コマンドを実行してみて,udf_example.soが生成されていれば大丈夫です。

$ ls | grep udf_example.so
udf_example.so

上記のようにlsとgrepを組み合わせて,出力されたものが正しく存在するか,確認してみましょう。

UDFを登録する

作成した.soファイルを/usr/lib64/mysql/pluginに配置します。

$ sudo cp udf_example.so  /usr/lib64/mysql/plugin

その後に,UDFを使うために以下のようなコマンドをmysqlコマンドラインクライアントから実行します。

CREATE FUNCTION 関数名 RETURNS 戻り値の型名 SONAME 今回作ったudfのファイル名といった構文になっております。今回コンパイルを行ったudf_example.ccには7個の関数が同梱されており,その中で今回は例としてlookup関数を取り上げてみます。

mysql> CREATE FUNCTION lookup RETURNS STRING SONAME 'udf_example.so';
Query OK, 0 rows affected (0.00 sec)

すると,lookup関数が登録されて使用するできるようになります。localhostのIPを引いてみましょう。

mysql> select lookup('localhost');
+---------------------+
| lookup('localhost') |
+---------------------+
| 127.0.0.1           |
+---------------------+
1 row in set (0.00 sec)

このように,ホスト名からIPを引くような関数を追加することができました。ここまでで,関数を新たに追加できるようになりましたが,追加したlookup関数を削除する場合にはどうしたら良いか,気になると思います。関数の削除をしたい場合は,DROP FUNCTION構文を利用します。

mysql> DROP FUNCTION lookup;
Query OK, 0 rows affected (0.00 sec)

削除を実行した後で,もう一度lookup関数を利用しようとしてみます。

mysql> select lookup('localhost');
ERROR 1046 (3D000): No database selected

エラーになって関数がなくなっていることがわかりました。

今回コンパイルを行ったudf_example.ccには,lookup関数以外にも,英単語の綴りから発音に近い文字列を出力するmetaphon関数,引数の平均値をとるmyfunc_double関数,引数の長さを測るmyfunc_int関数,シーケンス番号を発行することができるsequence関数,IPからドメインを引くためのreverse_lookup関数,集約関数のテスト用にavgcost関数が設定されており,それぞれ使うことができます。

まとめ

今回はUDFのコンパイルの方法,追加・実行・削除のそれぞれの方法について学びました。今回説明しきれなかったUDFのプログラムの構成や書き方などは,次に機会がある時に紹介していきたいと思っています。

著者プロフィール

木村浩一郎(きむらこういちろう)

GMOメディア株式会社 技術推進室所属のWebアプリケーションエンジニア。最近はミドルウェア・インフラ周りのことも少しずつ学習しています。趣味は将棋。好きな戦法は四間飛車。

Twitter:@kk2170

コメント

コメントの記入