sql-mode: Emacs から SQL 文を実行する
bash などの高機能シェルが提供するコマンド補完や行編集機能にどっぷり漬かってしまうと、 SQL Plus(Oracle の SQL クライアント)や isql(SQL Server が提供する SQL クライアント)が提供する貧弱な編集機能が使い辛くて我慢ならないことがありますが、sql.el を利用すれば Emacs の強力な編集機能を利用した SQL 文の記述・実行が可能になります。
概要
sql.el
は Alex Schroeder
氏がメンテナンスしている SQL 用の Emacs Lisp であり、sql-mode / sql-interactive-mode
という二つのメジャーモードを提供しています。
sql-mode はその名の通り、SQL 文を編集するためのモードであり、SQL 文に対する構文ハイライティングが行われます。 更に、後述する sql-interactive-mode へと編集中の SQL を送ることも出来ます。
sql-interactive-mode は SQL クライアントと対話するためのモードです。 ぶっちゃけた話、shell-mode でシェルが動作する代わりに SQL クライアントが動作している、と考えれば問題ないでしょう。 この「SQL クライアントが動作している」バッファを「SQLi バッファ」と呼びます。
入手とインストール
配布元
最近の Emacs には sql.el が含まれていますが、せっかくなので最新版を拾ってきましょう。
sql.el の最新版は http://www.geocities.com/kensanata/elisp/ から取得出来ます。ここには sql.el を始めとして、以下のような SQL 関係の Emacs Lisp が置かれています。
| 名前 | バージョン | 説明 |
|---|---|---|
sql.el |
1.6.3 | SQL インタプリタ用の comint |
sql-indent.el |
1.1.2 | SQL 文のインデント |
sql-transform.el |
2.2.0 | SQL 文の変換 |
sql-complete.el |
0.0.1 | テーブル / カラムの補完機能 |
master.el |
1.0.2 | 現在のバッファから他のバッファのスクロールを行う |
インストール
普通の Emacs Lisp ですから、普通の Emacs Lisp らしくインストールして、.emacs
に設定をすれば完了です。
「説明を聞くのも面倒だ」という人は、とりあえず上記 5 つのファイルを site-lisp
あたりにブチ込んでから、以下の設定を .emacs に追加しておくと幸せになれるかもしれません。
;;; ;;; sql-mode ;;; http://www.emacswiki.org/cgi-bin/wiki.pl?SqlMode ;;; (autoload 'sql-mode "sql" "SQL Edit mode" t) (autoload 'sql-oracle "sql" "SQL Edit mode" t) (autoload 'sql-ms "sql" "SQL Edit mode" t) (autoload 'master-mode "master" "Master mode minor mode." t) ;; SQL mode に入った時点で sql-indent / sql-complete を読み込む (eval-after-load "sql" '(progn (load-library "sql-indent") (load-library "sql-complete") (load-library "sql-transform") )) ;; デフォルトのデータベースの設定 (setq sql-user "scott") (setq sql-database "orcl") ;; SQL モードの雑多な設定 (add-hook 'sql-mode-hook (function (lambda () (setq sql-indent-offset 4) (setq sql-indent-maybe-tab t) (local-set-key "\C-cu" 'sql-to-update) ; sql-transform ;; SQLi の自動ポップアップ (setq sql-pop-to-buffer-after-send-region t) ;; master モードを有効にし、SQLi をスレーブバッファにする (master-mode t) (master-set-slave sql-buffer) )) ) (add-hook 'sql-set-sqli-hook (function (lambda () (master-set-slave sql-buffer)))) (add-hook 'sql-interactive-mode-hook (function (lambda () ;; 「;」をタイプしたら SQL 文を実行 (setq sql-electric-stuff 'semicolon) ;; comint 関係の設定 (setq comint-buffer-maximum-size 500) (setq comint-input-autoexpand t) (setq comint-output-filter-functions 'comint-truncate-buffer))) ) ;; SQL モードから SQLi へ送った SQL 文も SQLi ヒストリの対象とする (defadvice sql-send-region (after sql-store-in-history) "The region sent to the SQLi process is also stored in the history." (let ((history (buffer-substring-no-properties start end))) (save-excursion (set-buffer sql-buffer) (message history) (if (and (funcall comint-input-filter history) (or (null comint-input-ignoredups) (not (ring-p comint-input-ring)) (ring-empty-p comint-input-ring) (not (string-equal (ring-ref comint-input-ring 0) history)))) (ring-insert comint-input-ring history)) (setq comint-save-input-ring-index comint-input-ring-index) (setq comint-input-ring-index nil)))) (ad-activate 'sql-send-region)
基本的な使い方
M-x sql-help で簡単なヘルプが出てきますが、一応ざっと解説します。
SQLi バッファを開く
Emacs から各種 SQL クライアントを起動する方法は各 SQL クライアントごとに異なりますが、基本的には「 M-x sql-XX 」という形になっています。
各 SQL クライアントを起動する方法の一覧を挙げておきます。 見ての通り沢山の RDBMS (に付属の SQL クライアント)がサポートされていますが、私が知っているのは Oracle と Microsoft SQL Server だけですので、 これ以降の記述はほぼ全てこの両 RDBMS に特化したものとなります。悪しからず。
| RDBMS | 関数 | SQL クライアント |
|---|---|---|
| PostgreSQL | sql-postgres |
psql |
| MySQL | sql-mysql |
mysql |
| SOLID | sql-solid |
solsql |
| Oracle | sql-oracle |
sqlplus |
| Informix | sql-informix |
dbaccess |
| SQL Server(Sybase) | sql-sybase |
isql |
| Ingres | sql-ingres |
sql |
| SQL Server(Microsoft) | sql-ms |
isql |
| InterBase | sql-interbase |
isql |
| DB2 | sql-db2 | db2 |
Oracle の場合であれば M-x sql-oracle を実行するとユーザ名、パスワード、接続文字列が尋ねられ、SQL Plus が起動します。SQL Server の場合は M-x sql-ms を実行するとユーザ名、パスワード、サーバ名、データベース名が尋ねられ、isql が起動します。 これらの「SQL クライアントが起動しているバッファ」こそが「SQLi バッファ」です。
SQLi バッファには SQL クライアントのプロンプト
(Oracle の SQL Plus であれば「SQL> 」)が表示されており、端末から利用するのと同様の感覚で
SQL クライアントを利用出来ます。
なお、SQL Server の isql では SQL 文を入力した後に、
「go 」を入力しないと、SQL 文が実行されないということに注意して下さい。
SQLi バッファが正しく開かない場合は、環境変数
PATH に利用する SQL クライアントが置かれているディレクトリが含まれているかどうかを確認しましょう。
例えば、Microsoft SQL Server の SQL クライアントである isql は
c:\Program Files\Microsoft SQL Server\80\Tools\Binn などにインストールされているはずです。
SQL クライアントへ引数を与える
SQL クライアントにオプションを与えたい場合は、事前に変数
sql-XX-options にそのオプションを指定しておきます。
各 RDBMS ごとの変数は以下のようになっていますが、全ての RDBMS でオプションが指定出来るわけではありません。
| RDBMS | 変数 |
|---|---|
| PostgreSQL | sql-postgres-options |
| MySQL | sql-mysql-options |
| Oracle | sql-oracle-options |
| SQL Server(Sybase) | sql-sybase-options |
| InterBase | sql-interbase-options |
| DB2 | sql-db2-options |
また、デフォルトのユーザ名やサーバ名などの接続に必要な情報は、それぞれ以下のような変数で設定出来ます。
| 変数名 | 意味 |
|---|---|
sql-user |
デフォルトのユーザ |
sql-passwd |
デフォルトのパスワード |
sql-database |
デフォルトの接続先データベース(Oracle の場合は接続文字列) |
sql-server |
デフォルトの接続先サーバ |
SQLi バッファと isql の問題
Microsoft SQL Server の isql は、SQLi バッファでは何故か出力が乱れます。 端末から isql を利用した場合は
$ isql -S server -U user -P passwd
1> select top 1 * from tb_ikan
2> go
EMP_NO OLD_DEPT_CD NEW_DEPT_CD
----------- ------------ ------------
1177 1001 1002
(1 row affected)
1> exitと表示されるのに対して、SQLi バッファでは、
select top 1 * from tb_ikan
go
1> 2> EMP_NO OLD_DEPT_CD NEW_DEPT_CD
----------- ------------ ------------
1177 1001 1002
exit
(1 row affected)
1>
Process SQL finishedのように表示されてしまいます。原因はわかりません。
sql-mode
デフォルトでは拡張子 .sql のファイルを開くと、SQL モードに入ります。
が、これだけでは sql-mode は単なる「プログラミング言語用モード」であり、SQL
文がハイライトされるだけのものでしかありません。
sql-mode の機能をフルに利用するなら、先に述べた方法で
SQLi バッファを事前に開いておく必要があります(*1) 。
sql-mode 上で SQL 文を書き、行の最後(別に最後じゃなくてもよいのですが)でおもむろに C-c C-c を叩くと、SQLi バッファでその SQL 文が実行されます。但し C-c C-c では一行しか SQLi バッファに送ることが出来ませんから、バッファ単位やリージョン単位で送る場合は、別のキーバインドを利用します。
| キーバインド | 関数 | 説明 |
|---|---|---|
| C-c C-b | sql-send-buffer |
バッファの内容を SQLi バッファに送る |
| C-c C-r | sql-send-region | リージョンの内容を SQLi バッファに送る |
| C-c C-c | sql-send-paragraph |
現在の行を SQLi バッファに送る |
実際のところ、一行で完結するような簡単な SQL 文ならそれこそ sql-mode なぞ使わずに SQLi
バッファで実行すればよいのですから、一番使うのは
sql-send-region かもしれません。
複数行に渡る SQL 文を Emacs の編集機能を利用してガンガン編集し、最後に
sql-send-region するのが良いと思います。
なお、SQLi バッファに SQL 文を送ったときに
SQLi バッファをポップアップさせるには、sql-pop-to-buffer-after-send-region に
t を設定しておきます。
sql-interactive-mode
SQLi バッファで利用されているモードが sql-interactive-mode です。ですが sql-interactive-mode は SQLi バッファでしか利用出来ないので、以後は「SQLi バッファ」で統一します。
SQLi バッファは comint(command interpreter)の機能を利用していますから、shell-mode などで使い慣れた M-p や M-n などが使えます。つまり SQL Plus では出来なかった「履歴を手繰る」、或いは「行編集」などが出来るわけです。
SQLi バッファ独自の機能として C-c C-w (sql-copy-column)があります。
SQL ではその性質上、どうしてもカラムを沢山並べなければならない状況が頻発しますが、
そのような場合にこれを利用できます。が、大げさな名前の割にやっていることはごく単純で、
カーソルがある位置の単語をバッファの最後にコピーしているだけです。
まず、カラムの一覧をバッファに表示するために「desc テーブル名 」などを実行します。
カラムの一覧が表示されたら、目的のカラムの上にカーソルを移動し、おもむろに
C-c C-w を実行すると、バッファの最後にそのカラム名がコピーされます。
しかも連続して実行すれば途中のカンマを補ってくれるというおまけつきです。
後は「SELECT」や「WHERE」などを追加してやれば、あっという間に SQL 文の完成です。
…などと書くと何とも凄そうにみえますが、個人的にはいちいちカラムを探して
C-c C-w するくらいなら、素直に「desc テーブル名」(Oracle の場合)した後に
abbrev を使ったほうが楽だとは思っています。
適切な設定を行わないと利用出来ないのですが、「; 」をタイプすると即座に
SQL 文が実行されるという機能もあります。変数 sql-electric-stuff に semicolon
を定義(*2)しておけばこの機能が有効になります。
便利だと思うかどうかは人それぞれなので、試してみて下さい。
SQL 文の自動インデント
sql-mode で SQL 文の自動インデントを行うには、sql-indent.el を利用します。
sql-indent-offset でタブ位置を好みの位置に設定し、必要であれば
sql-indent-maybe-tab に t を設定する程度で十分でしょう。
master.el を利用する
master.el は、他のバッファ(スレーブバッファと呼びます)のスクロールを、
現在のバッファ(マスタバッファと呼びます)から行うためのマイナーモードです。
SQL モードをマスタバッファとし、SQLi バッファとスレーブバッファとして利用すると、SQL モードで
SQL 文を書きながら、SQLi バッファをスクロールさせることが出来ます。
組み込み方については冒頭に挙げた例を参照して下さい。
なお、Meadow 1.14 では master.el に以下のパッチを当てないと駄目なようです。
--- master.el.orig Thu Apr 25 22:10:27 2002 +++ master.el Thu Apr 25 22:10:52 2002 @@ -69,7 +69,7 @@ ;;; Define master mode. ;;;###autoload -(define-minor-mode master-mode +(easy-mmode-define-minor-mode master-mode "Toggle Master mode. With no argument, this command toggles the mode. Non-null prefix argument turns on the mode.
SQL バッファから SQLi バッファのスクロールを制御するには、以下のキーバインドを利用します。
| キーバインド | 関数 | 説明 |
|---|---|---|
| C-c C-l | master-says-recenter |
SQLi バッファのカーソル位置をバッファ中央へ移動する |
| C-c > | master-says-end-of-buffer |
SQLi バッファのカーソル位置を SQLi バッファの終端へ移動する |
| C-c < | master-says-beginning-of-buffer |
SQLi バッファのカーソル位置を SQLi バッファの先頭へ移動する |
| C-c C-p | master-says-scroll-down |
SQLi バッファを下へスクロールする |
| C-c C-n | master-says-scroll-up |
SQLi バッファを上へスクロールする |
なお、master モードの状態については M-x master-show-slave で知ることが出来ます。