DB操作ツール Emacs DBI を作ってみた

去年からほそぼそと作ってきた、EmacsからDBを操作できるツール Emacs DBI を紹介します。

Emacs DBI の簡単な紹介

このツールの目的は、クロスプラットフォームで便利なDB操作環境を実現することです。 pgAdmin や MySQL Query Browser のようなGUIの良さをCUIで実現してみようとしてみました。すなわち、ぼくのかんがえたさいきょうのDBツールです。ちなみに、このツールにとってEmacsはただの実行環境です。Emacs使わない人でも使うと便利だと思います。



データベース画面



e2wmで3ペインの画面

機能概要

以下のような機能があります。

  • EmacsとDB接続可能なPerlが動けばターミナルでも何処でも動く
  • DB定義、テーブル定義がすぐ見れる
  • auto-complete によるSQL補完
    • 接続先DBにからキーワード、型名、テーブル名、カラム名などを補完
  • 対応DB(この日記時点)

簡単に仕組みを説明しますと、EmacsのUIから自前RPC(SWANKっぽいS式のプロトコル)でPerlに接続し、PerlのDBIを使ってDB接続するというものです。

インストール

Perlのモジュールとelispを入れる必要があります。

どちらもパッケージシステムを使うことによって、コマンド一発で入れることが出来るのですが、環境によってはうまく動かないかもしれません。多分そんなに難しくないとは思いますが、EmacsとPerl/CPANの知識があるとスムーズです。

手元での動作確認は、以下の環境で確認しています。

CPAN

以下のCPANモジュールを入れます。

cpan 使うときのコマンド例

cpan RPC::EPC::Service DBI DBD::SQLite DBD::Pg DBD::mysql

自分の所ではシステム全体のCPANと分けるために cpanm を使っています。

LinuxやMacならこれで入ると思います。Windowsで手軽に使うにはActivePerlがいいみたいです。
Cygwinを使っている人は多いと思いますが、Cygwin Perl はPerl以外の依存関係を自力解決する必要があります。

Windows : Cygwin Perl
CygwinのSetup.exeから、Perl や gcc-4 や SQLite などの開発パッケージを入れて、CPANコマンドで入れると入るはずです。CygwinのCPANが遅いのでちょっと時間がかかります。その場合は、 cpanm を使うと速くていいです。

CPANでのビルドに失敗した場合は、build.logを見ながら依存ライブラリを追加すると大丈夫みたいです。

Windows : ActivePerl
(2012/03/07 修正)
ActivePerlのppmで一発インストールできます!
ppm install RPC-EPC-Service
Marmalade を使ったelispの全自動インストール

Marmalade package システムが入っていれば、 M-x list-package して、「edbi」というパッケージを探してインストール操作するだけです。必要な依存ライブラリやPerlプログラムがすべてインストールされます。あとは設定へ進んでください。

elispの手動インストール

Marmaladeを使わない場合のインストール方法です。
まずは以下の elisp をインストールします。

  • deferred.el
  • concurrent.el
  • ctable.el
  • epc.el
  • edbi.el
;; auto-installを使う場合
(auto-install-from-url "https://github.com/kiwanami/emacs-deferred/raw/master/deferred.el")
(auto-install-from-url "https://github.com/kiwanami/emacs-deferred/raw/master/concurrent.el")
(auto-install-from-url "https://github.com/kiwanami/emacs-ctable/raw/master/ctable.el")
(auto-install-from-url "https://github.com/kiwanami/emacs-epc/raw/master/epc.el")
(auto-install-from-url "https://github.com/kiwanami/emacs-edbi/raw/master/edbi.el")

後は perl のプログラムが必要です。
以下のリンクから edbi-bridge.pl をダウンロードして edbi.el と同じ所に置いてください

設定と動作確認

scratchバッファで (require 'edbi) とやって、 M-x 'edbi:open-db-viewer としてDB接続画面が出ればひとまずOKです。ここでエラーが出る場合は、必要な elisp が入っていない可能性があります。

次回起動時から使えるように、 ~/.emacs.d/init.el などの各自の設定ファイルに以下のように追加します。

(autoload 'edbi:open-db-viewer "edbi")

使い方説明

各画面を簡単に説明します。後で画面遷移についてもまとめます。

接続

M-x edbi:open-db-viewer で接続ダイアログが開きます。



接続ダイアログ

「Data Source」にはDBIで接続するときの書き方で、接続先のDB情報を書きます。以下、書き方の例です。

  • sqlite : dbi:SQLite:dbname=/path/to/abcd.sqlite
  • postgresql : dbi:Pg:dbname=abcd (※abcd というDBに接続する場合)
  • mysql : dbi:mysql:abcd (※abcd というDBに接続する場合)
  • 詳細は DBIのドキュメントや各DBDのドキュメントを参照してください。

「User Name」「Auth」には、接続のためのユーザー名とパスワードを入れます。ユーザー名やパスワードが必要ないDBは入力する必要はありません。

一度接続確立したら、Data Source と User Name は履歴に残りますので、次回からは「History」をクリックするかボタンの上でRETすると選択できます。履歴は edbi:ds-history-file に保存されます。(履歴の編集機能は現在ありません。)

接続の際にエラーが発生すると、エラーの内容が上の方に表示されます。接続情報に間違いがなければインストールに問題があるかもしれません。トラブルシューティングの項を参照してください。

DB定義画面

Emacs DBI のホーム的な画面です。接続先のテーブルやビューの一覧が表示されます。
ここから各テーブルの定義やクエリーの内容を表示します。



DB定義画面

主なキーバインドです。

キー 動作
j,k,n,p 選択の上下移動
SPC 選択したテーブルの定義表示
RET 選択したテーブルのデータ表示
c クエリーエディタ開く
g 最新の情報に更新
q Emacs DBI 終了

(詳しくは edbi:dbview-keymap と ctbl:table-mode-map を参照してください。)

テーブル定義画面

テーブルやビューの定義を表示します。カラムの名前・型・サイズや主キーやNOT NULLなどの情報を見ることができます。



テーブル定義画面

主なキーバインドです。

キー 動作
j,k, n,p 上下移動
V テーブルのデータ表示
c クエリーエディタ開く
g 最新の情報に更新
q バッファkill

(詳しくは edbi:dbview-table-keymap と ctbl:table-mode-map を参照してください。)

クエリーエディタ画面

このバッファでSQLを書きます。C-c C-c でSQL実行、 M-p / M-n で過去に実行したSQLを表示できます。
sql-mode をベースにしたメジャーモードになっていて、適当なシンタックスハイライトと、auto-completeが入っていれば補完が効いて、Emacsのエディタの能力を生かして効率よくSQLを書くことができます。



エディタ画面

主なキーバインドです。

キー 動作
C-c C-c SQL実行
M-p 履歴もどる
M-n 履歴すすむ
C-q q Emacs DBI 終了

(詳しくはedbi:sql-mode-map を参照してください。)

現在のところ、SQLの履歴はEmacsを終了すると消えてしまいます。

クエリー結果画面

SQLの結果を見やすいテーブルで表示します。



結果画面

主なキーバインドです。

キー 動作
j,k,n,p 上下移動
h,l,b,f 左右移動
a,e 左端、右端移動
q バッファkill

SELECTでないSQLの場合は、影響を受けた行数が表示されます。
(ただし、DBIドライバの実装によってはなんだかよく分からない値になることがあります。)

画面遷移

これまでの画面の遷移をまとめると以下のようになります。



画面遷移

終了、接続の後始末

Emacs DBI を終了するには、DB定義画面(*edbi-dbviewer* バッファ)で q を押します。その際、関連するバッファも一緒に消してしまっていいかどうかの確認が出ます。普通は消してしまっていいと思います。

DB定義画面を普通にkillしてしまうと、DB接続だけが残ってしまう場合があります。そんな時は、 M-x epc:manager とすると、現在接続中のEPCが一覧で出てきます。この画面で必要ない接続の行に移動して「D」を押すと接続を消すことができます。EPCについては別のエントリでやると思います。



EPC接続画面

トラブルシュート

予想されるトラブルと対応方法を簡単にまとめました。
近所に Emacs や Perl のハッカーが一人はいると思いますので、うまく動かない場合は相談されるといいと思います。

  • LC_ALLとかLANGのロケールが不明というエラー
    • (setenv "LC_ALL" "ja_JP.utf8") とか評価すると動くかもしれません。
  • 「file-error Searching for program そのようなファイルやディレクトリはありません perl」
    • Emacsからperlが見つけられないというエラーです。
    • Perlをインストールするか、Emacsから見えるところにパスを通す必要があります。
  • 「error Server may raise an error : Can't open perl script "〜/edbi-bridge.pl": そのようなファイルやディレクトリはありません (以下略」
    • edbi-bridge.pl が見つからないというエラーです
    • edbi.el と同じディレクトリにあれば大丈夫のはずです
    • うまく行かない場合は、手動で edbi:driver-libpath ã‚’ edbi-bridge.pl のあるディレクトリに設定してみてください。
  • 「error Server may raise an error : Can't locate RPC/EPC/Service.pm in @INC (@INC contains: ...(以下略」
    • Perlモジュールが見つからないというエラーです
    • RPC::EPC::Service などのインストールか、インストール先のCPANのディレクトリが見えてない可能性があります
    • 環境によっては AnyEvent が動かない場合もあるようです
  • その他
    • バグや要望などは github の issue に書いていただくと、対応するかもしれません。ご期待にそえなかった場合はすいません。
    • バグの場合はSQLiteで動くけどこのDBでは動かないみたいな調査があると大変助かります。

まだまだ開発途上ですので、バグや不便なところがたくさんあると思います。

カスタマイズ

変数、フック、キーマップ
  • テーブル簡易データ表示の LIMIT 件数。デフォルトは50。
    • edbi:dbview-show-table-data-default-limit
  • 長い文字列の切り捨て文字数。デフォルトは 50。
    • edbi:query-result-column-max-width
  • 固定ヘッダーか、バッファ内ヘッダーか。デフォルトは t (固定ヘッダー)
    • edbi:query-result-fix-header
    • 固定だと縦スクロールしてもヘッダーが表示されるが、横スクロールすると切れてしまう
    • バッファ内ヘッダーだと横スクロールしても問題ないが、縦スクロールで切れてしまう
  • クエリー編集バッファの mode-hook
    • edbi:sql-mode-hook
  • キーマップ
    • ctbl:table-mode-map : テーブルの基本キーマップ
    • edbi:dbview-keymap : DB定義画面のキーマップ
    • edbi:dbview-table-keymap : テーブル定義画面のキーマップ
    • edbi:sql-mode-map : クエリー編集画面のキーマップ
    • edbi:dbview-query-result-keymap : クエリー結果画面のキーマップ
e2wmとの連携

e2wmのパースペクティブにすることで、GUIアプリのようにウインドウの構成を固定して使うことができます。



e2wm 画面

利用方法は、以下の elisp を e2wm の後で読み込むように設定します。

この例では「Super+D」でDB画面になるように設定しています。

キー一発でコードとDB操作を切り替えることができるので、Webアプリ開発のようなコードとDBを頻繁に参照するような開発に威力を発揮します。

別のDBMSへの対応

現在のところ、SQLite, MySQL, Postgresql と、id:buzztaiki さんにパッチをいただいた Oracle に対応しています。これ以外のDBMSについては、PerlのDBD(DBIのドライバ)があれば原理的に対応可能です。ただし、DBDやDBMSによってAPIの仕様や返り値がかなり異なるため、そのままでは動かない可能性が高いです。

他のDBMSへの対応を追加する方法は以下のようです。

  • githubの edbi-demo.el をポチポチ実行しながらDBDからの返り値を確認
  • 他のDBMSのものを参考にしながら edbi:dbd 構造体を定義
  • edbi:dbd-register で登録して接続しなおして動作確認

もし、いい感じに追加対応ができたら、 pull request を送っていただけたら取り込みたいと思います。

今後の展開

以下、自分が現在考えている希望です。実現するかどうかは未定です。

  • 対応DBの追加
    • ADO.NET, odbc とか
    • mongoDBなど、DBI以外のDBもつながると便利そう
  • テーブル定義画面の充実
    • インデックス情報の取得 (現在SQLiteしか取れてない)
    • Foreign Key 情報
  • クエリー関係
    • よく使うSQLの保存機能、Anythingで選択とか
    • 段階的データ取得(現在は全部取ってきてしまう)
    • LIMITはかっこ悪い(fetchを使ってるので、実際にはプログラムから途中で止めることが出来る)
    • auto-complete で文脈をみて補完できると良さそう
  • データ操作機能
    • レコードの詳細表示(長いテキストは切れるので)
    • テーブルにINSERTする機能

あとがき

そもそも、このツールをつくろうと思ったのは、Linux用の良いDB操作用GUIツールが無かったからです。

開発の時はSQLをたくさん書くので、補完もシンタックスハイライトも欲しいですし、テーブル定義も頻繁に見たいです。コンソールだとそのあたりのサポートが全く無いので不便でした。

Emacs には sql-mode や inferior な sql-interactive-mode もありますが、自分にとっては console がちょっと便利になった程度でしかないので、コンソールに比べてメリットが感じられませんでした。

  • コンソールUIの問題
    • 結果表示が貧弱
    • コマンド打たないと何も見えない
      • DBMSによってコマンドが異なる
    • 途中改行するSQLが書きづらい

一方、GUIのアプリは、結果がテーブルの形で表示されるので見やすく、またテーブルの定義情報へのアクセスも容易です。さらに、GUIでテーブルやDBMSの管理が行えたり、Explainの結果を見やすく整形できたり、便利な機能がたくさんあります。

自分が使ったり試したりしたことがあるDB操作のGUIツールには以下のものがあります。

Windows にはたくさんGUIツールがあるのですが、Mac版は殆どありません。LinuxはMacよりはましですが、常用できるツールはほとんど無いです。IDE統合のツールはどのOSでも動いて便利そうなのですが、わざわざこのためにIDE起動したくありません。

軽くて、どのOSでも同じように動いて、GUIのツールぐらい便利に使えて、Emacs並にエディタが強力なDB操作ツールが欲しいのです。

ということで、無いなら作ろうという事で、去年の calfw が一段落した後から作り始めました。途中、派生ツールとして epc / ctable などが出来ました。

今では日常的にEmacs DBIを使っていますが、大変幸せな毎日を送っています。

次回予定やお知らせ

以下の内容を予定しています。

  • Emacs用汎用RPCスタック epc
  • 汎用テーブルビュー ctable
  • Emacs用のDB接続API edbi

また、3/31の Fukuoka Perl Workshop #21 にて、Emacs DBI や epc の内部の動きなどについて発表しようかなと考えています。@lestrrat さんや @nekokak さんも来られるそうですので、ぜひどうぞ!