PostgreSQLのclient_encodingをdatabase.ymlのdsnで指定する
先日の続き。id:iakioさんのコメントから。ありがとうございます:-)
実はpg_connect(”options=’-c client_encoding=euc-jp’”);という書き方もできるので、
options: ’-c client_encoding=euc-jp’
でいけるかもしれません。
dsnで書けるんだろうなぁと思いつつ調べてませんでしたが、なるほど「-c」だったのかぁ。で、早速書いて。。。ん?DSNだと、どうやって書くんだ?
しょうがないので、コードを追ってみました。database.ymlの内容をparseしているのは、symfony/addon/propel/database/sfPropelDatabase.class.phpのaddConfigメソッドで、その中でsymfony/vendor/creole/Creole.phpのparseDSNメソッドを使ってました。実装ですが、
<?php : public static function parseDSN($dsn) { if (is_array($dsn)) { return $dsn; } : $info = parse_url($dsn); :
URL扱いかっ!結果を見てみると、QUERY_STRINGに相当するのがoptionsになる模様。そこでdatabase.ymlに
dsn: pgsql://dbuser:dbpass@localhost:5432/service_db?options='-c client_encoding%3dutf8'
と書くと、うまくoptionsに「'-c client_encoding=utf8'」と入ります。
でも、sfPropelDatabase.class.phpのaddConfigメソッドでは、
<?php : public function addConfig() { : require_once('creole/Creole.php'); $params = Creole::parseDSN($dsn); $options = array('phptype', 'hostspec', 'database', 'username', 'password', 'port', 'protocol', 'encoding', 'persistent', 'socket','compat_assoc_lower','compat_rtrim_string', 'options'); foreach ($options as $option) { if (!$this->getParameter($option) && isset($params[$option])) { $this->setParameter($option, $params[$option]); } } :
と、折角parseしたoptionsを考慮していないので、そもそも無理。
ということで、やっぱりパッチを作りました。
*** symfony/addon/propel/database/sfPropelDatabase.class.php.org 2008-06-28 18:05:42.000000000 +0900 --- symfony/addon/propel/database/sfPropelDatabase.class.php 2008-06-28 18:15:31.000000000 +0900 *************** *** 68,74 **** require_once('creole/Creole.php'); $params = Creole::parseDSN($dsn); ! $options = array('phptype', 'hostspec', 'database', 'username', 'password', 'port', 'protocol', 'encoding', 'persistent', 'socket','compat_assoc_lower','compat_rtrim_string'); foreach ($options as $option) { if (!$this->getParameter($option) && isset($params[$option])) --- 68,74 ---- require_once('creole/Creole.php'); $params = Creole::parseDSN($dsn); ! $options = array('phptype', 'hostspec', 'database', 'username', 'password', 'port', 'protocol', 'encoding', 'persistent', 'socket','compat_assoc_lower','compat_rtrim_string', 'options'); foreach ($options as $option) { if (!$this->getParameter($option) && isset($params[$option])) *************** *** 95,100 **** --- 95,101 ---- 'socket' => $this->getParameter('socket'), 'compat_assoc_lower' => $this->getParameter('compat_assoc_lower'), 'compat_rtrim_string' => $this->getParameter('compat_rtrim_string'), + 'options' => $this->getParameter('options'), ), ); }
これで、前のパッチなしにちゃんと接続できました。なお、optionsに使うクオートはシングルクオートじゃないとダメです。って、何だこれは?
ちなみに、database.ymlに
all: propel: class: sfPropelDatabase param: phptype: pgsql hostspec: localhost username: dbuser password: dbpass database: service_db persistent: true options: -c client_encoding=utf8 port: 5432
と書くと、最終的にpg_connect/pg_pconnectする際の接続文字列が
host=localhost port=5432 dbname='service_db' user='dbuser' password='dbpass' options=-c client_encoding=utf8
と、なぜかoptionsにクオートが付きません。というか、symfony/vendor/creole/drivers/pgsql/PgSQLConnection.phpのconnectメソッドで、なぜか
- dbname
- user
- password
しかクオートが付いてません。これも、
*** symfony/vendor/creole/drivers/pgsql/PgSQLConnection.php.org 2008-06-28 18:42:39.000000000 +0900 --- symfony/vendor/creole/drivers/pgsql/PgSQLConnection.php 2008-06-28 18:42:39.000000000 +0900 *************** *** 87,93 **** $connstr .= ' password=\'' . addslashes($dsninfo['password']) . '\''; } if (!empty($dsninfo['options'])) { ! $connstr .= ' options=' . $dsninfo['options']; } if (!empty($dsninfo['tty'])) { $connstr .= ' tty=' . $dsninfo['tty']; --- 87,93 ---- $connstr .= ' password=\'' . addslashes($dsninfo['password']) . '\''; } if (!empty($dsninfo['options'])) { ! $connstr .= ' options=\'' . $dsninfo['options'] . '\''; } if (!empty($dsninfo['tty'])) { $connstr .= ' tty=' . $dsninfo['tty'];
のようにしてやれば、とりあえず文字化けせずに接続できます。
うーん。やっぱりsymfonyとPostgreSQLは相性が悪い。。。というより、あまり考慮されてない感じがするなぁ。バージョンアップとかあとで面倒なことになるので、できるだけ触らないようにしたいけど、前途多難だ。。。orz