検証環境への導入ネタの最後。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 用のバグ対応が溜まってきた・・・。早めに本家に報告したいなぁ。