MySQLのストアドプロシージャを調査する

Oracleでは、USER_PROCEDURESとUSER_ARGUMENTSから
プロシージャと引数の一覧が作れたりするが、MySQLではどうなっているのか調査。

下準備

以前にXOOPSを入れたときのXAMMPが残っていたのでそれを利用してみる。
データは MySQL用のSCOTTデータベース - SH2の日記 からscottさんのスキーマを拝借。
MySQLのバージョンは5.0.67-community-ntとなっている。
コマンドプロンプトで作業するのもつらいのでMySQLのページからMySQL GUI Toolsをダウンロードしてきてインストール。

調査対象を作る

まずはプロシージャを作らねば話にならない。
こんな感じでてきとうに作成。使い慣れた*1PL/SQLと勝手が違うので戸惑う。

DELIMITER $$

DROP PROCEDURE IF EXISTS `GetSalGrade` $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `GetSalGrade`(in   pGrade decimal(10,0),
                                                          out  pLow   decimal(10,0),
                                                          out  pHigh  decimal(10,0))
BEGIN
  select  losal
        , hisal
  into    pLow
        , pHigh
  from    salgrade
  where   grade = pGrade;
END $$

DELIMITER ;
DELIMITER $$

DROP FUNCTION IF EXISTS `GetEmpCount` $$
CREATE DEFINER=`root`@`localhost` FUNCTION `GetEmpCount`() RETURNS int(11)
BEGIN
  declare cnt int(11);
  select count(empno) into cnt from emp;
  return cnt;
END $$

DELIMITER ;

パッケージ仕様と本体に別れてはいないらしい。
Oracleのように[TABLENAME].[COLUMNNAME]%typeとかやってカラムの型を取得することはできないようだ。
ついでに、カーソルのフェッチ時もレコード変数なんてものはなく、
1つずつ丹念に手作業で変数に格納してやらなければならないようだ。*2

調査する

スキーマのリストを眺めてみると、mysqlといういかにもなスキーマがある。
もう一つinformation_schemaというこれまたいかにもな名前のヤツがあるが、
とりあえずmysqlから調べることにする。
……funcとprocの2つのテーブルが臭そうだ。
とりあえずselect * を実行してみる。


funcは空だ。何のテーブルかは疑問だが後回しにしてprocでselect *してみる。
…とさっき作ったプロシージャ名が出て来た。
MySQLではprocテーブルにストアドプロシージャの情報が格納されるようだ。
引数は…………それらしいテーブルはない。
procテーブルをよく見ると、param_listなんて列がある。
引数はここにBLOB型で格納されるようだ。
戻り値はreturns列に格納されている。


information_schemaの方も調べてみると、routinesテーブルにストアドプロシージャの情報が格納されていた。
よく調べていないが、こちらは引数等の細かい情報ではなく全体的な情報が格納されているようだ。
routine_definition列(LONGTEXT型)でソースが取得できる。
procテーブルのbody列(こちらはBLOB型)でもソースが取得できるが、body列の方は
一番外のBEGIN〜END;までしか格納されていない。(関数の定義?部がない)

結論

  • MySQLではprocテーブルにストアドプロシージャの情報が格納される
  • 引数はmysql.proc.param_listにblob型で格納される
  • 戻り値はmysql.proc.returnsに"int(11)"のように型名が格納される*3

*1:とは言っても、まともにPL/SQLを使ったのは今の仕事が初めて。内緒だけど。SQLPascal(Delphi)が分かればなんとかなるもんだ。

*2:本当はあるのかもしれないが、http://dev.mysql.com/doc/refman/5.1/ja/cursors.html を見る限りではないように思える。

*3:戻り値がない場合は空白となる。NULLではない。