MT4.01でブログを書くボタンを押すとエラーが出る件に無理矢理対処した話

 WordPressで運用しているサイトにMTのことを書くのもアレなのですが。
 X-Serverで稼働しているマンガ感想サイトで使用しているMovable Type 4.01ですが、記事が15件になった時点で「ブログを書く」ボタンを押すと、

Statement has no result columns to bind (perhaps you need to successfully call execute first) at (MTをインストールしたディレクトリ)/extlib/Data/ObjectDriver/Driver/DBI.pm line 120.

 というエラーが発生するようになりました。
 一度データを削除してインポートし直しても、別データベースを作ってそこにデータをインポートしても、データベースに復旧をかけても、全然このエラーが解消しません。エラーメッセージで検索をかけても解決方法を書いているところはないようで、どうも一度出たらもうダメ系のエラーっぽいです。

 DBI.pm のエラーが出ている箇所を色々調べた結果、”SELECT config_id, config_data FROM mt_config WHERE (config_id IN (?))“(? はブログID。こちらの環境では1) という SQL を実行し、bind_columns で config_id と config_data の値を配列に設定しようとしているところで発生しているということは判りましたが、でも判ったところでどうしようもないというか、何故ここでこんなエラーが出るのかまでは判りませんでした。MySQLやDBIのバージョンに依存する問題なのかも知れません(MySQL 4.0.25, DBIのバージョンは不明)。
 ただ、エラーが出る部分のSQLは正直それほど重要なものではなさそうなので、これって別に無視してもいいんじゃね? みたいなことを思ったのも事実。

 仕方がないので、エラーが出る箇所を eval で囲み、エラーを無視するという行き当たりばったりな対処をしてみたところ、「ブログを書く」ボタンを押してもエラーが発生しなくなり、そのまま記事を書いて保存できるようになりました。
 何だかよく判りませんが、とりあえずこれで問題には対処できたので、一応ここで修正したコードを公開しておきます。

extlib/Data/ObjectDriver/Driver/DBI.pm の 120行目以降を、以下のように修正

    eval { $sth->bind_columns(undef, @bind); };
    if (!$@) {
      # need to slurp 'offset' rows for DBs that cannot do it themselves
      if (!$driver->dbd->offset_implemented && $args->{offset}) {
          for (1..$args->{offset}) {
              $sth->fetch;
          }
      }
    } else {
      warn $@;
      $sth->fetch;
    }

    # TBD what happens if $sth goes out of scope without finish() being called ?

※これによって何が起こっても私は一切関知しません。自己責任でお願いします!

MT4にはてなスターを設置する

 MT4.01で運営しているマンガ感想サイトに、はてなスターを設置しました。
 MTにはてスタを設置する方法ははてスタ日記に紹介されているのですが、MT4用の設定が書いてあるのに気付いたのは設置した後でした(ヘボ)。
 結果的に、紹介されているのとは違う方法で実装することに成功したっぽいので紹介します。

 はてなスターは「h3」タグがエントリのタイトルとして使用していることを前提としているのですが、MT4の標準のテンプレートでは普通のインデックスでは「h2」を、個別の記事では「h1」をエントリのタイトルとして使用しているので、その辺を修正する必要があります。

ダッシュボード→デザイン→テンプレート→テンプレートモジュール→ヘッダーを選択し、headタグの範囲の適当な位置に以下のコードを追加:

<!-- インデックスページ用 -->
<MTIf name="main_index">
<script type="text/javascript" src="http://s.hatena.ne.jp/js/HatenaStar.js"></script>
<script type="text/javascript">
Hatena.Star.EntryLoader.headerTagAndClassName = ['h2','asset-name'];
Hatena.Star.Token = 'あなたのトークン';
</script>
</MTIf>

<!-- 個別のエントリ用 -->
<MTIf name="entry_archive">
<script type="text/javascript" src="http://s.hatena.ne.jp/js/HatenaStar.js"></script>
<script type="text/javascript">
Hatena.Star.Token = 'あなたのトークン';
Hatena.Star.EntryLoader.loadEntries = function() {
var entries = [];
var divs = Ten.DOM.getElementsByTagAndClassName('h1','asset-name',document.body);
entries.push(new Hatena.Star.Entry.MT4Blog(divs[0]));
return entries;
}
Hatena.Star.Entry.MT4Blog = new Ten.Class({
initialize: function(h1) {
this.title = Ten.DOM.scrapeText(h1);
this.uri = document.URL;
this.comment_container = Hatena.Star.EntryLoader.createCommentContainer();
h1.appendChild(this.comment_container);
this.star_container = Hatena.Star.EntryLoader.createStarContainer();
h1.appendChild(this.star_container);
}
});
</script>
</MTIf>

 インデックスページ(main_index)は h2タグの class=”asset-name” がエントリのタイトルになっているので、「Hatena.Star.EntryLoader.headerTagAndClassName = [‘h2′,’asset-name’];」と記述すれば良いです。
 個別のエントリ(entry_archive)の場合は、h1タグの class=”asset-name” がエントリのタイトルになっているのですが、デフォルトではエントリのタイトルがaタグで括られていないので、単にHatena.Star.EntryLoader.headerTagAndClassNameで設定しただけではスターが適応されません。なので、はてスタ日記に書かれているlivedoor blog用のコードを修正し、h1のasset-nameのみを抽出してそこにスターを適応するコードを追加しています。
 こうすることにより、個別エントリのテンプレートを修正しなくても、ヘッダーのテンプレートを修正するだけでスターを適応できるというメリットがあります。

 もし「はてスタのためだけにエントリのタイトルにaタグを入れるのはイヤだ!」という拘りがある方は、上記の方法を試して頂くといいかも知れません。