Hatena::ブログ(Diary)

技術日記@kiwanami

2012-03-05

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

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

Emacs DBI の簡単な紹介

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

e2wmで3ペインの画面

機能概要

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

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

インストール

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

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

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

CPAN

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

cpan 使うときのコマンド例

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

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

LinuxMacならこれで入ると思います。Windowsで手軽に使うにはActivePerlがいいみたいです。

Cygwinを使っている人は多いと思いますが、Cygwin PerlPerl以外の依存関係を自力解決する必要があります。

Windows : Cygwin Perl

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

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

Windows : ActivePerl

(2012/03/07 修正)

ActivePerlppmで一発インストールできます!

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情報を書きます。以下、書き方の例です。

「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接続画面


トラブルシュート

予想されるトラブルと対応方法を簡単にまとめました。

近所に EmacsPerlハッカーが一人はいると思いますので、うまく動かない場合は相談されるといいと思います。

  • LC_ALLとかLANGのロケールが不明というエラー
    • (setenv "LC_ALL" "ja_JP.utf8") とか評価すると動くかもしれません。
  • 「file-error Searching for program そのようなファイルやディレクトリはありません perl
  • 「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: ...(以下略」
  • その他
    • バグや要望などは 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の追加
  • テーブル定義画面の充実
  • クエリー関係
    • よく使う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版は殆どありません。LinuxMacよりはましですが、常用できるツールはほとんど無いです。IDE統合のツールはどのOSでも動いて便利そうなのですが、わざわざこのためにIDE起動したくありません。

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

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

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

次回予定やお知らせ

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

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

通りすがり通りすがり 2012/03/27 00:25 自分も以前似たようなものがほしいと思い、odbcを使ってemacs版とブラウザ版(activex)作りました。
小さいウィンドウを操れるブラウザが便利だったのでemacs版は止まってしまいましたが、edbiは非常に便利なツールだと思います。
がんばってください!
SQLエディタ部分は、compltionを構文解析した結果でやりたいなと思っているので、がんばってみようと思います。

T-YusukeT-Yusuke 2012/05/25 01:21 kiwanami様

はじめまして、T-Yusukeと申します。
Emacs DBI、便利に使用させてもらっています。
ただ、Firebirdというデータベースに対応していなかったため、対応するコードを付け加えてみた所、他のデータベース同様に動くようになりました。

もし迷惑でなければ、一度コードを見てはもらえないでしょうか。
何かとお忙しいとは思いますが、上記の件ご検討頂ければ幸いです。

kiwanamikiwanami 2012/05/27 10:19 はい! github で pull request とかいただけると助かります。他の方法でも大丈夫です。

T-YusukeT-Yusuke 2012/05/27 14:46 kiwanami様

お返事ありがとうございます。私は github のアカウントを持っていないので、変更内容のdiffを取ったものをzipでまとめました。以下のURLからダウンロード出来ます。
一度ご確認ください。

https://skydrive.live.com/redir?resid=6863FE1EDE01B424!106

T-YusukeT-Yusuke 2012/05/28 20:37 kiwanami様

昨日アップロードした"edbi.zip"ですが、ファイル内容の一部に間違いがありましたので、修正しました。修正後のzipファイルは"edbi_20120528.zip"です。ファイルは以下のURLからダウンロード出来ます。

https://skydrive.live.com/redir?resid=6863FE1EDE01B424!107

修正内容は以下の通りです。

 ・DBD::InterBase.pmにおいて、パラメータ付きのクエリを投げなければいけない所を単純に文字列を結合したクエリを投げていた

いろいろとややこしい事になって申し訳ありませんが、確認頂ければ幸いです。

kiwanamikiwanami 2012/05/29 01:05 すごい丁寧な修正内容ありがとうございます。ちょっとDB環境を準備して確認してみます。

taktak 2013/02/11 07:30 便利に使わせていただいています。
ちょっと困ったことがおきてしまったのですが、今までUTF-8の日本語を正常に表示できていたのですが、うっかりEUCでINSERT文を書いてしまって(たぶんこれが原因だと思うのですが・・・)それ以来UTF-8が文字化けするようになっていしまいました。
環境はUbuntu + mysql5.5 + emacs24.1.1です。
文字化けの前後で設定ファイルなどはいじっていません、なぜ化けるようになってしまったのか、原因がさっぱりわかりません、なんとか直らないものでしょうか?

taktak 2013/02/11 08:19 肝心なことを書き忘れました。文字化けする db(table) と EUC で書き込んでしまった db は別のものです。

kiwanamikiwanami 2013/02/12 21:55 Perlより上側のEmacs側はUTF8と決め打ちで動いているはずので、おそらくPerl側でなにか起きているのではないかと思われます。が、ちょっと状況がこちらでもよくわかりません。
通常の mysql コンソールとかでどうなるかとか、databaseの定義をshow create database ... とかで見てみて、DBの文字コードを確認してもらっていいでしょうか。

taktak 2013/02/13 04:04 kiwanami 様、ご返信ありがとうございます。
通常の mysql コンソールでは文字化けは起きません。
database 定義、create database などでの db 文字コードは全て UTF-8 でした。

いろいろ調べてみたところ、"set names utf8" をSQLコマンドとして(?)DBIから実行すると文字化けが直ることがわかりました。
しかし、一度接続を切ってしまうと再接続したときにまた文字化けするので念のためmy.cnfに'skip-character-set-client-handshake'
を追加したところ、文字化けが直りました。
何故、最初の状態で'skip-character-set-client-handshake'無しで文字化けせずに表示できていたのかなど原因がよくわかりませんが、症状としては直りましたので御報告させて頂きます。

お手数をおかけしてしまい申し訳ありませんでした。

kiwanamikiwanami 2013/02/14 14:19 現象が改善されたようでよかったです。
文字化けの対応方法も参考になりました。ご報告ありがとうございます。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証