astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

SQLからC言語を呼ぶ方法 ~MeCab編~

前書き

お久しぶりでございます。Scalaでバックエンドを開発しているaxtstar(@axtstart)です。

ずいぶん昔になりますが、OracleDBでアプリ開発をしていたころ、DBの中でデータが(なぜか)バイナリで格納されていて、そのビット演算を行いながら検索するみたいな案件をやったことがあります。はじめはアプリサイドからSQLで頑張って演算していたのですが、あまりにも遅くて、結局OCI(Oracle Call Interface)を利用して、C++でバイナリを扱うように書き換えたら激的に速度が改善したことがありました。

今回ふと思い立ち、Postgresqlってそういうことができるのかしら?と思い至り今回のブログ担当を利用して検証してみることにしました。

なので、(確実に)プロダクション環境で実施するのははばかられるような内容ですのでご注意下さい。

f:id:astamuse:20200729085523p:plain

使用できる言語は...

ちなみに、今回対象としたPostgresqlはDockerHubから持ってきたpostgresql:latestを対象としています。

select version();

結果

version
PostgreSQL 12.3 (Debian 12.3-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit

現時点*1だとPostgreSQL12.3のようです。

上記imageの初期状態で、Postgresqlで使用できる言語は下記でした。

select * from pg_language;

結果

oid lanname lanowner lanispl lanpltrusted lanplcallfoid laninline lanvalidator
12 internal 10 False False 0 0 2246
13 c 10 False False 0 0 2247
14 sql 10 False True 0 0 2248
13398 plpgsql 10 True True 13395 13396 13397

なんと~デフォルトでcの文字がありますね!

どうやるのか?

OracleのOCIにあたるものがないのか調べているとspi(Server Programming Interface)というものがあることがわかりました。

Oracleの場合と同様、PL/SQL(PostgresだとPL/pgsql)からC/C++で書かれたプログラムを何らかの与えられた方式で呼び出せばよい感じ。

libpqというのを初めに見つけましたが、こちらはPro*C*2みたいなものっぽいですね。

  • C/C++ から SQLを呼び出す(libpg) ←これじゃない
  • SQLからC/C++を呼び出す(spi) ←これ

Server Programming Interface(spi)

PostgresqlはC言語とのインターフェースにサーバプログラミングインターフェースという名前の機構を用意していて、ユーザ定義のC関数をSQLから呼び出すことができるようです。

調べた限りだと、ソースコードのビルドに必要なパッケージとして以下が必要でした。*3

※imageのpostgresql:latestからの差分として必要という意味です。

apt-get install -y make clang llvm gcc postgresql-server-dev-12

またdb serverのインストール時にpg_configというプログラムが同時にインストールされ、これが様々な情報を教えてくれるようです。

例えば、PostgreSQLのサーバプログラム作成用のCヘッダファイルの格納パスとか

pg_config --includedir-server

結果

/usr/lib/postgresql/12/lib

詳しくはこちら

また、どのように作成するのかというのもかなり詳しくマニュアルに記載がありました。

C言語関数の部分を要約すると

  • 共有ライブラリとして作成すること(so、dll、dylib)
  • バージョン互換性マクロを一度だけ記述すること
  • 「version 1」呼び出し規約をサポートすること
  • 参照渡しの入力値の内容を決して変更しないこと*4

などなど。。。

なので結構マクロを多用する実装になるようです。

作るもの

せっかくなので、ちょっとだけ実用になりそうな(気がする)ものをサンプルで作ってみます。今回は、MeCabをインストールしてそちらを呼び出して、結果を返すことにします(本当はC言語のライブラリがあるので対象として適切だったのが本音)。

とはいってもこちらはメインではないのでサクっとaptで導入します

apt-get install -y mecab libmecab-dev mecab-ipadic-utf8

※MeCabの詳しい記事は↓こちら↓からどうぞ~ lab.astamuse.co.jp

作るものはこんな流れになります。

No 使用マクロ 意味
1 PG_MODULE_MAGIC 非互換性のチェック
2 PG_FUNCTION_INFO_V1(function) 関数宣言
3 Datum function(PG_FUNCTION_ARGS) Version-1呼び出し規約、引数引き渡し
4 PG_GETARG_xxx() SQLからの引数取得
5 palloc/palloc0 メモリアロケーション(マクロではない。。と思います。)
6 SET_VARSIZE サイズ確保
7 PG_RETURN_xxx() SQLへの返却設定

できたソース

ビルド用のmakefileはこちら

ビルドしてインストールしておきます

make
make install

下記ディレクトリにmecab_simple.soという名前で配置されます

/usr/lib/postgresql/12/lib

このユーザ定義関数を呼び出すにはファンクションとして定義する必要があります。

CREATE FUNCTION mecab(text) RETURNS text
     AS 'mecab_simple', 'mecab'
     LANGUAGE C STRICT;

その際、パス、ファイル名に関しては以下のルールに従います

第一引数

  • 絶対パス
  • 名前が$libdirという文字列から始まる場合、その部分はPostgreSQLパッケージのライブラリディレクトリ
  • 名前にディレクトリ部分がない場合、そのファイルはdynamic_library_path設定変数で指定されたパス内
  • 拡張子(.so、.dll、.dylib)を補って上記パスを検索
  • 上記以外は失敗

第二引数

  • 省略時は第一引数と同じとみなす
  • 指定時は関数

結果

f:id:astamuse:20200729011832p:plain
すもも

おお!どうやらうまくいったみたいですね!!

上記の一式をDockerfileでまとめているので、 ↓こちらに置いておきます。

github.com

おまけ

デフォルト機能ではないのですが、Postgresqlの拡張機能にplpython3uというものがあり、Postgresqlからpythonのスクリプトが実行できるようです。

事前準備として、postgresql-plpython3-12といったパッケージが必要なようです。

事前準備

apt-get install -y postgresql-plpython3-12

Postgresql上でExtensionを有効にします。

CREATE EXTENSION plpython3u;

Pythonのバージョンを確認してみます。

ファンクションを定義します。

CREATE FUNCTION pyversion()
  RETURNS text
AS $$
  import sys
  return sys.version
$$ LANGUAGE plpython3u;

バージョン確認

select pyversion();

結果

3.7.3 (default, Dec 20 2019, 18:57:59) 
[GCC 8.3.0]

こちらも機会があればもう少し調べてみたいと思いました。

最後に

Oracleと同様PostgresqlでもC/C++の呼び出しはサポートされていました。今回速度検証まではできませんでした、また、このような組み込みモジュールを使うのは一般的ではないかもしれないですが、マクロが充実していて、以前のOracleの時よりは楽にプログラミングできる印象*5でした。またpythonを利用するのも比較的簡単に実現できたので、こちらはもう少し深堀したくなりました。

最後になりましたが、アスタミューゼでは現在、エンジニア・デザイナーを絶賛大大大募集中です! 興味のある方はぜひ下記バナーからご応募ください!!

*1:2020/07/28現在

*2:もう比喩が若い人に通じない話をしているかもしれない

*3:条件によってはさらに必要かもしれません。

*4:変更すると、ディスク上のデータを破壊してしまうかもしれません。とのこと。。こわい

*5:llvmなどその他の技術の発展のおかげかもしれませんが。。。

Copyright © astamuse company, ltd. all rights reserved.