前に書いた「PostgreSQL:複数定義があるFunctionの一覧をクエリで取得する」って記事の続き的なもの。すっかり書くの忘れてましたが。
さて、上にあげた記事のように、うちのPJではめちゃくちゃFunctionが多くて色々と問題が起きておりまして。そのうえ、環境ごとにDBが乱立してしまい、あるDBのFunctionが最新版では無かったりして環境ごとに挙動が異なり、混乱を招いたりするのは日常茶飯事でした。
もう完全に管理できてへんやんけ!という本音は横に置いておき、ひとまず事態を収めねばなりません。幸い、FunctionそのものはテキストファイルにしてSVN上で保存してあったので、最新版を当て直すだけならば、さほど難しくありません。
しかし、どうせ当て直しするなら消し忘れの古い定義のFunctionとか、不要になったFunctionとか、一括して整理したいなぁと思いまして。なんか一括で消せないのかなーと思って調べたのですが、特にそういう機能は無いらしく、1個ずつ手動で消すのはあまりにも面倒だったので、↓みたいな方法で消すことにしました。
◆FunctionでFunctionを消す
やり方は単純で、システムテーブルからFunction名とか引数定義とかを引っ張ってきて、動的SQL文を作って削除するってのを繰り返すだけです。らくちんね。
自分自身を消さないようにしたり、対象を絞るようにするのを忘れないでください。例えば弊社の場合は、関数名の先頭に「fn_」ってつけることが規則になっていたので、絞り込むのは簡単でした。
・システムテーブルからFunction名と引数定義を取得する
SELECT nmsp.nspname || '.' || pgp.proname || '(' || pg_catalog.oidvectortypes(pgp.proargtypes) || ')' AS functionName FROM pg_catalog.pg_proc pgp LEFT JOIN pg_catalog.pg_namespace nmsp ON nmsp.oid = pgp.pronamespace WHERE pgp.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype AND NOT pgp.proisagg AND nmsp.nspname = 'public' AND pgp.proname like 'fn_%' ;
これを実行すると、publicに定義されてる、名前がfn_ではじまるfunction一覧が引数の型定義とセットで手に入ります。「名前(引数1の型, 引数2の型)」みたいな形で。あとはこれを、「DROP FUNCTION 名前(引数1の型, 引数2の型);」という文字列に加工してやって、ループで動的SQLとして実行し続ければOKです。
・動的SQLとしてDROP文を実行する
DECLARE rec_funcname_list record; txt_sql text; BEGIN FOR rec_funcname_list IN SELECT nmsp.nspname || '.' || pgp.proname || '(' || pg_catalog.oidvectortypes(pgp.proargtypes) || ')' AS functionName FROM pg_catalog.pg_proc pgp LEFT JOIN pg_catalog.pg_namespace nmsp ON nmsp.oid = pgp.pronamespace WHERE pgp.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype AND NOT pgp.proisagg AND nmsp.nspname = 'public' AND pgp.proname like 'fn_%' LOOP txt_sql = 'DROP FUNCTION ' || rec_funcname_list.functionName; execute txt_sql; END LOOP; END;
エラー処理とかは省略してます。実際に使ってるやつからは若干改変してます。(ほんとちょとだけ)
先に書いたSQLの結果件数だけループさせて、「execute txt_sql;」で実行し続けるだけの簡単なfunctionです。
使う場合には自己責任でどうぞ。(事前に、SELECT部分だけ実行してちゃんと目的のものだけになってるか、は目を通しておいたほうがいいと思います)