PostgreSQL 8.3.xだとリポジトリブラウザが見えない
2008/07/15 追記:
類似の不具合が判明したので併せて修正しています。
会社が変わったので、別PC上でOSその他もろもろ最新バージョンにあげてみたのですが、
Tracのリポジトリブラウザが見えないと言う状況が発生しました。
インストールしているもろもろのバージョンはこんな感じです。
OS | CentOS 5.1 |
---|---|
PostgreSQL | 8.3.1 |
Python | 2.5.2 |
DB Driver? | pyPgSQL 2.5.1 |
Trac | 0.10.4-ja-1 |
subversion | 1.4.6 |
以下は、その原因ならびに対応方法です。
せっかちな人用に先にパッチを書いておきます。
$TRAC_ROOT/lib/python2.5/site-packages/trac/versioncontrol/cache.py
を以下のように変更すれば、動作しました。
旧:
246: cursor.execute("SELECT time,author,message FROM revision " 247: "WHERE rev=%s", ((rev),)) : 257 cursor.execute("SELECT path,node_type,change_type,base_path,base _rev " 258 "FROM node_change WHERE rev=%s " 259 "ORDER BY path", (self.rev,))
新:
246: cursor.execute("SELECT time,author,message FROM revision " 247: "WHERE rev=%s", ((str(rev)),)) : 257 cursor.execute("SELECT path,node_type,change_type,base_path,base _rev " 258 "FROM node_change WHERE rev=%s " 259 "ORDER BY path", ((str(self.rev)),))
以下は、事象の発生から原因特定まで。
普通にTracをインストールして、リポジトリブラウザを表示すると、
以下のようなコールスタックがでてしまいます。
Traceback (most recent call last): File "/opt/trac/lib/python2.5/site-packages/trac/web/main.py", line 406, in dispatch_request dispatcher.dispatch(req) File "/opt/trac/lib/python2.5/site-packages/trac/web/main.py", line 237, in dispatch resp = chosen_handler.process_request(req) File "/opt/trac/lib/python2.5/site-packages/trac/versioncontrol/web_ui/browser.py", line 143, in process_request self._render_directory(req, repos, node, rev) File "/opt/trac/lib/python2.5/site-packages/trac/versioncontrol/web_ui/browser.py", line 168, in _render_directory changes = get_changes(self.env, repos, [i['rev'] for i in info]) File "/opt/trac/lib/python2.5/site-packages/trac/versioncontrol/web_ui/util.py", line 37, in get_changes changeset = repos.get_changeset(rev) File "/opt/trac/lib/python2.5/site-packages/trac/versioncontrol/cache.py", line 45, in get_changeset self.authz) File "/opt/trac/lib/python2.5/site-packages/trac/versioncontrol/cache.py", line 247, in __init__ "WHERE rev=%s", ((rev),)) File "/opt/trac/lib/python2.5/site-packages/trac/db/util.py", line 50, in execute return self.cursor.execute(sql_escape_percent(sql), args) File "/opt/trac/lib/python2.5/site-packages/trac/db/util.py", line 50, in execute return self.cursor.execute(sql_escape_percent(sql), args) File "/opt/python/lib/python2.5/site-packages/pyPgSQL/PgSQL.py", line 3111, in execute raise OperationalError, msg OperationalError: ERROR: operator does not exist: text = integer LINE 1: SELECT time,author,message FROM revision WHERE rev=56 ^ HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
原因は多分これでしょう。
OperationalError: ERROR: operator does not exist: text = integer
LINE 1: SELECT time,author,message FROM revision WHERE rev=56
文字列と数値を比較すんなってことですね。
まずは、データベースのテーブルの内容を確認してみます。
Table "public.revision" Column | Type | Modifiers ---------+---------+----------- rev | text | not null time | integer | author | text | message | text | Indexes: "revision_pkey" PRIMARY KEY, btree (rev) "revision_time_idx" btree ("time")
確かに文字列でした。古いマシン上(PostgreSQL 8.2.4)でもテーブル構成は一緒です。
何が違うか比べてみました。
旧 | 新 | unmutch | |
---|---|---|---|
Trac | 0.10.4-ja-1 | 0.10.4-ja-1 | |
DB Driver? | pyPgSQL 2.5.1 | pyPgSQL 2.5.1 | |
Python | 2.5.1 | 2.5.2 | x |
PostgreSQL | 8.2.4 | 8.3.1 | x |
OS | Fedora Core3 | CentOS 5.1 | x |
一番簡単そうなDBから手をつけることにしました。
上記でエラーとなったSQL「SELECT time,author,message FROM revision WHERE rev=56」を
8.2.4と、8.3.1上で直接実行してみました。
見事に、8.3.1だけこけます。
理由を調べてみました。
ostgreSQL 8.3 に関する技術情報
に、以下のような記述があります。
今までは text 型入力を受けとる演算子や関数に文字でない値が渡されると、自動的に text 型にキャストしていました。 これからは text 型でないデータを渡したい場合には text 型への明示的なキャストが必要になります。 例えば以前は以下の式が動作していました。
これっすね。いろいろ理由はあるみたいですが、、、
余計なことすんなぁぁぁ!!!
じゃぁ、明示的にキャストなりクォートで囲むなりすればいいんだなと思って、
コールスタックを元に調べてみましたよ。
で、pyPgSQL君へきちんとStringTypeの変数を渡せば怒られない事を下記サンプルで
確認できたので、上記のような対応にいたるわけです。
import pyPgSQL.PgSQL con = pyPgSQL.PgSQL.connect("localhost:5432:tableName:uid:password") rev=56 cur = con.cursor() cur.execute("SELECT time,author,message FROM revision " "where rev=%s", ((str(rev)),)) cur.close() con.close()
どっちが作法的によろしくないかと言えばTracなんだけど、OracleもMySQLもこれは通るよなぁ。。。
それに、偏見かもしれないけど、LLって型付け弱いからせめて、テーブルのメタ情報から類推してほしいなぁ。。。
#でも、そうなると遅くなる可能性もかなり高いからなぁ。
やっぱ型はきちんと意識しようぜってことです。