miau's blog?

古い PostgreSQL で CakePHP の fixture が動かない件

検証環境への導入ネタの最後。CakePHP で fixture 使ったテストをやってると、

Query: ALTER SEQUENCE "public.actions_id_seq" RESTART WITH 1

# Error
Unexpected PHP error [pg_query() [function.pg-query]: Query failed: ERROR: relation "public.actions_id_seq"
does not exist] severity [E_WARNING] in [/***/cake/libs/model/datasources/dbo/dbo_postgres.php line 148]
/***/app/tests/cases/components/upload.test.php -> UploadComponentTestCase -> testUpload

こんなこと言われる。PostgreSQL 8.3.6 の環境だとちゃんと動くけど、7.4.16 だとダメらしい。以下詳細と対応方法。




■軽く調査

エラーになったクエリを 7.4.16 の psql 上で叩いてみる。

ALTER SEQUENCE "public.actions_id_seq" RESTART WITH 1

やっぱりエラー。

8.3.6 のほうはどうなの?と思ったら発行されているクエリが違ってて、

ALTER SEQUENCE "actions_id_seq" RESTART WITH 1

なんてのが発行されている。なんで片方だけスキーマついてるの?

■処理を追ってみる

発行されているクエリは両方とも

SELECT DISTINCT column_name AS name, data_type AS type, is_nullable AS null,
column_default AS default, ordinal_position AS position, character_maximum_length AS char_length,
character_octet_length AS oct_length FROM information_schema.columns
WHERE table_name = 'actions' AND table_schema = 'public'

みたいな感じ。

これが 8.3.6 上だと

name | type | null | default | position | char_length | oct_length
------------+-----------------------------+------+-------------------------------------+----------+-------------+------------
created | timestamp without time zone | NO | now() | 4 | |
id | integer | NO | nextval('actions_id_seq'::regclass) | 1 | |
modified | timestamp without time zone | NO | now() | 5 | |
name | text | NO | | 2 | | 1073741824
sort_order | integer | NO | | 3 | |
(5 rows)

こうなって、7.4.16 上だと、

name | type | null | default | position | char_length | oct_length
------------+-----------------------------+------+----------------------------------------+----------+-------------+------------
created | timestamp without time zone | NO | now() | 4 | |
id | integer | NO | nextval('public.actions_id_seq'::text) | 1 | |
modified | timestamp without time zone | NO | now() | 5 | |
name | text | NO | | 2 | | 1073741824
sort_order | integer | NO | | 3 | |
(5 rows)

こうなると。

この nextval('〜')の部分を解析することで、CakePHP はシーケンスの名称を得ていると。

■解決策は?

ちゃんと通るようにするには、

ALTER SEQUENCE "public"."actions_id_seq" RESTART WITH 1

のようにスキーマとテーブル名を個別にクォートしてやるか、

ALTER SEQUENCE public.actions_id_seq RESTART WITH 1

のようにクォートしなければいいっぽい。

まあ今回は楽するためクォートしない方向で対応してみる。

Index: cake/libs/model/datasources/dbo/dbo_postgres.php
===================================================================
--- cake/libs/model/datasources/dbo/dbo_postgres.php (revision 8202)
+++ cake/libs/model/datasources/dbo/dbo_postgres.php (working copy)
@@ -365,9 +365,9 @@
if (isset($this->_sequenceMap[$table]) && $reset !== 1) {
foreach ($this->_sequenceMap[$table] as $field => $sequence) {
if ($reset === 0) {
- $this->execute("ALTER SEQUENCE \"{$sequence}\" RESTART WITH 1");
+ $this->execute("ALTER SEQUENCE {$sequence} RESTART WITH 1");
} elseif ($reset === -1) {
- $this->execute("DROP SEQUENCE IF EXISTS \"{$sequence}\"");
+ $this->execute("DROP SEQUENCE IF EXISTS {$sequence}");
}
}
}

※他の対応も入れているので行数ずれてるかも。

これでちゃんと動くようになりました。

それにしても、なんか PostgreSQL 用のバグ対応が溜まってきた・・・。早めに本家に報告したいなぁ。
posted at 00:15:18 on 2009-03-27 by miau - Category: General No Trackbacks - Permalink

TrackBack

このエントリにトラックバックはありません
現在トラックバックは受け付けていません。

Comments

No comments yet

Add Comments

現在コメントは受け付けていません。
お手数ですが、 こちら のコメント欄にでも記載していただければと思います。