読者です 読者をやめる 読者になる 読者になる

Windows版の pdo-mysql で MYSQL_ATTR_READ_DEFAULT_FILE が未定義だった

PHP の PDO でキャラクタセットを指定するときは次の様に行なっています。

$pdo = new PDO("mysql:host=127.0.0.1;dbname=test", $username, $password, array(
	PDO::MYSQL_ATTR_READ_DEFAULT_FILE  => '/etc/my.cnf',
	PDO::MYSQL_ATTR_READ_DEFAULT_GROUP => 'php',
));


Zend_Db の場合は次の様に 'driver_options' で指定します。

$db = Zend_Db::factory('Pdo_Mysql', array(
	'host'     => '127.0.0.1',
	'username' => 'user',
	'password' => 'pass',
	'dbname'   => 'test',
	'driver_options' => array(
		PDO::MYSQL_ATTR_READ_DEFAULT_FILE  => '/etc/my.cnf',
		PDO::MYSQL_ATTR_READ_DEFAULT_GROUP => 'php',
	),
));


が、この方法を Windows版のPHP(5.3.3 と 5.3.13)で試してみたところ PDO::MYSQL_ATTR_READ_DEFAULT_FILE や PDO::MYSQL_ATTR_READ_DEFAULT_GROUP が定義されていないためにエラーになりました。

Fatal error: Undefined class constant 'MYSQL_ATTR_READ_DEFAULT_FILE'


リフレクションで見てみると、確かに PDO::MYSQL_* の定数の内、Windows版だと幾つかが定義されていませんでした(逆にWindows版だけで定義されているものもあり)。


拡張モジュールのソースを見てみると・・・「ext/pdo_mysql/pdo_mysql.c」で以下の通りになっていました。

static PHP_MINIT_FUNCTION(pdo_mysql)
{
	REGISTER_INI_ENTRIES();

	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_USE_BUFFERED_QUERY", (long)PDO_MYSQL_ATTR_USE_BUFFERED_QUERY);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_LOCAL_INFILE", (long)PDO_MYSQL_ATTR_LOCAL_INFILE);	
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_INIT_COMMAND", (long)PDO_MYSQL_ATTR_INIT_COMMAND);
#ifndef PDO_USE_MYSQLND
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_MAX_BUFFER_SIZE", (long)PDO_MYSQL_ATTR_MAX_BUFFER_SIZE);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_READ_DEFAULT_FILE", (long)PDO_MYSQL_ATTR_READ_DEFAULT_FILE);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_READ_DEFAULT_GROUP", (long)PDO_MYSQL_ATTR_READ_DEFAULT_GROUP);
#endif
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_COMPRESS", (long)PDO_MYSQL_ATTR_COMPRESS);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_DIRECT_QUERY", (long)PDO_MYSQL_ATTR_DIRECT_QUERY);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_FOUND_ROWS", (long)PDO_MYSQL_ATTR_FOUND_ROWS);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_IGNORE_SPACE", (long)PDO_MYSQL_ATTR_IGNORE_SPACE);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_KEY", (long)PDO_MYSQL_ATTR_SSL_KEY);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CERT", (long)PDO_MYSQL_ATTR_SSL_CERT);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CA", (long)PDO_MYSQL_ATTR_SSL_CA);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CAPATH", (long)PDO_MYSQL_ATTR_SSL_CAPATH);
	REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CIPHER", (long)PDO_MYSQL_ATTR_SSL_CIPHER);
	return php_pdo_register_driver(&pdo_mysql_driver);
}

PDO_USE_MYSQLND が定義されているかどうかで、PDOの定数の定義が変わるようです。


それでは PDO_USE_MYSQLND はどこで定義されているのか見てみると・・・「ext/pdo_mysql/config.m4」と「ext/pdo_mysql/config.w32」にありました。

ext/pdo_mysql/config.m4
  if test "$PHP_PDO_MYSQL" = "mysqlnd"; then
    dnl enables build of mysqnd library
    PHP_MYSQLND_ENABLED=yes
    AC_DEFINE([PDO_USE_MYSQLND], 1, [Whether pdo_mysql uses mysqlnd])
ext/pdo_mysql/config.w32
if (PHP_PDO_MYSQL != "no") {
	if (PHP_PDO_MYSQL == "yes" || PHP_PDO_MYSQL == "mysqlnd") {
		AC_DEFINE('PDO_USE_MYSQLND', 1, 'Using MySQL native driver');
		STDOUT.WriteLine("INFO: mysqlnd build");
		EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c");
		ADD_EXTENSION_DEP('pdo_mysql', 'pdo');
	} else {
		if (CHECK_LIB("libmysql.lib", "pdo_mysql", PHP_PDO_MYSQL) &&
				CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_PDO_MYSQL", PHP_PHP_BUILD + "\\include\\mysql;" + PHP_PDO_MYSQL)) {
			EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c");
		} else {
			WARNING("pdo_mysql not enabled; libraries and headers not found");
		}
	}
}


m4 は詳しくありませんが、m4 の方だと特別指定しなければ libmysqlclient が使用され、w32 の方だと逆に mysqlnd が使われるようです(公式のWindows版バイナリも mysqlnd を使うようにビルドされている)。


CentOS5 の yum 版だと libmysqlclient の方でビルドされているので、Windowsでユニットテスト、プロダクションは CentOS などという場合に困りそうです。

dsn で charset を指定すれば解決な気もしますが、CentOS5 の yum 版が PHP-5.3.3 なので dsn に charset を指定しても効きませんし・・・