2015年12月10日木曜日

sqlplusのお供、rlwrapのオプションについて調べてみた

この記事は JPOUG Advent Calendar 2015 の10日目の記事です。

残念ながら私は全くOracleというDBMSが使えません。どれくらい使えないかというと、

SQL> SHOW DATABASES;
SP2-0158: unknown SHOW option "DATABASES"

( ゚д゚)ノ せんせー、このDBMSダメなやつです!

というくらい使えません。PostgreSQLだったらまだコマンドラインクライアントをゴニョって`SHOW DATABASES`で一覧を出すくらいのことは出来たんですが、sqlplusだとそういう訳にも行きませんね、このクローズドソース野郎!!1

という訳で、sqlplus使い御用達(と聞いている) rlwrap の話をしようと思います。わたしは groonga (コマンドラインクライアントの方)でrlwrapをよく使いますが、初めてオプションを調べてみたので記録しておきます。

有名な話だったらごめんなさい。


まずは単に起動。

$ rlwrap sqlplus

SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 7 18:52:56 2015

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

Enter user-name: supersuper
Enter password: **********


とまあこの通りパスワード部分はreadlineを通らず、"*"でマークされました。
Enter叩いた瞬間に"*"も消えました。sqlplus、こんな動作なのか。

そしてそこで有名なやつとして-aオプションを足してみると

$ rlwrap -a sqlplus

SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 7 18:59:45 2015

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

Enter user-name: supersuper
Enter password: top_s3cret


如何にもありそうな感じで、剥き出しでパスワードが表示される。本来、パスワードっぽいものを遠慮してreadlineに流さずにやってるのを、全部readlineに通してそのあとNL契機でsqlplusに渡してるんですね、たぶん。"*"の時と同じくエンター叩いた瞬間に消えますが、SQLのプロンプトで↑キーを押すと


SQL> top_s3cret

履歴に出た━━━━(゚∀゚)━━━━!!
readlineに渡るとhistory_fileにも書くからか。そうか、確かにそうだけど面白い。


$ rlwrap -a"Enter password:" sqlplus

SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 7 19:02:19 2015

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

Enter user-name: supersuper
Enter password: **********

-aオプションの直後(スペース文字を入れると、「スペース入れるな!」って怒られた)に指定した文字列が来た時は、パスワードだと見做してreadlineを通さなくなる、様子。
ちなみに"Enter password:"の状態で-aオプション *無し* の時でも *↑↓キーによる履歴呼び出しが可能* なので、一度パスワードが記録されると何となく雰囲気でログインできるかも知れない。


$ rlwrap -p"YELLOW" sqlplus

SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 7 19:15:38 2015

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

Enter user-name: supersuper
Enter password:

う、テキストべた張りだと感動が伝わらないと思いますが、プロンプトが全て黄色太文字になってます。
"yellow"だと太文字ではない様子。"RED"だと赤太文字、"red"だと赤細文字でした。へーすごい。MySQLでいうところの--pagerにカラーコード仕込む感じですね。でもこっちの方が英語で指定できていいなぁ。ってかmysqlコマンドラインクライアントもrlwrap経由で起動させてやれば 日々の覚書: MySQL 5.6以降のmysqlコマンドラインクライアントでプロンプトに色を付けるcmakeオプション なんてのも必要なくなりそう。うむ。


$ rlwrap -z"pipeto" sqlplus
..
SQL> SELECT * FROM ..; | less -S -r

そして極め付け。SQLの結果をそのまま別のプロセスにパイプで渡せるpipetoフィルター。mysqlにはpagerコマンドがあるので気楽にlessに食わせられるけれど、sqlplusにはお手軽なのがないらしい。

`-z"pipeto"`オプションを付けると、出力をパイプに向けられる。
( *出力を* 向けるので、パイプの手前までで出力が開始されてないとダメ。つまりSQLなら *セミコロンまで打ち込んでからパイプを付ける* 

ところでこれ、MySQLは文字列結合に"||"演算子を使わないから良いとして、Oracleはよく使いそう(偏見)なので、上手くやってくれ…

SQL> SELECT 'a' || 'b'; | wc

sh: -c: line 0: 期待してない token `|' のあたりにシンタックスエラー
sh: -c: line 0: `| 'b'; | wc'

  2

る訳がなかった。そりゃ別にsqlplus用のユーティリティーってわけじゃあるまいし。
幸いにしてフィルターの類はPerlで書かれているらしいので、ちょっと探してみる。


$ rpm -ql rlwrap
/usr/bin/rlwrap
/usr/share/doc/rlwrap-0.41
/usr/share/doc/rlwrap-0.41/AUTHORS
/usr/share/doc/rlwrap-0.41/COPYING
/usr/share/doc/rlwrap-0.41/NEWS
/usr/share/doc/rlwrap-0.41/README
/usr/share/man/man1/rlwrap.1.gz
/usr/share/man/man3/RlwrapFilter.3pm.gz
/usr/share/rlwrap
/usr/share/rlwrap/completions
/usr/share/rlwrap/completions/coqtop
/usr/share/rlwrap/completions/testclient
/usr/share/rlwrap/filters
/usr/share/rlwrap/filters/README
/usr/share/rlwrap/filters/RlwrapFilter.3pm
/usr/share/rlwrap/filters/RlwrapFilter.pm
/usr/share/rlwrap/filters/censor_passwords
/usr/share/rlwrap/filters/count_in_prompt
/usr/share/rlwrap/filters/ftp_filter
/usr/share/rlwrap/filters/history_format
/usr/share/rlwrap/filters/listing
/usr/share/rlwrap/filters/logger
/usr/share/rlwrap/filters/null
/usr/share/rlwrap/filters/paint_prompt
/usr/share/rlwrap/filters/pipeline
/usr/share/rlwrap/filters/pipeto
/usr/share/rlwrap/filters/scrub_prompt
/usr/share/rlwrap/filters/simple_macro
/usr/share/rlwrap/filters/template
/usr/share/rlwrap/filters/unbackspace

$ vim /usr/share/rlwrap/filters/pipeto
..
 50 sub input {
 51   my $input;
 52   $raw_input = $_;
 53   ($input, undef, $pipeline) =  /([^|]*)(\|(.*))?/;
 54   return $input;
 55 }
..

ここで切り分けているぽい。最初のパイプの手前までが元のコマンド、パイプの後ろがフィルターになってる。
そこでこんなパッチにしてみました。


*** /usr/share/rlwrap/filters/pipeto.orig       2010-01-03 21:42:16.000000000 +0900
--- /usr/share/rlwrap/filters/pipeto    2015-12-08 10:58:54.817411488 +0900
***************
*** 53 ****
!   ($input, undef, $pipeline) =  /([^|]*)(\|(.*))?/;
--- 53,54 ----
!   ($input, $pipeline) =  /(.+)?\s+\|\s+(.*)?/;
!   $input= $_ unless $input;

" | "(空白、パイプ、空白。空白は1つ以上の任意の個数でOK)をパイプと認識させるように変更。


SQL> SELECT 'a' || 'b' FROM dual /* パイプを通る */; | less
'A
--
ab

SQL> SELECT 'a' || 'b' FROM dual /* パイプを通らない */; |less
  2 

パイプを通らない場合、"|less"までをsqlplusが解釈しようとするのでちゃんと出力されませんね(これは-z"pipeto"を取ってもそんな動きだった)


ざっとマニュアルを読んで面白そうだったものの紹介でした!
(個人的にはパスワードプロンプトで↑↓使えたのが面白かった)

0 件のコメント :

コメントを投稿