From: uwendel at mysql dot com Operating system: Linux PHP version: 5.3CVS-2008-02-18 (CVS) PHP Bug Type: PDO related Bug description: Several PDO attributes are documented with the wrong type
Description: ------------ PDO->getAttribute() returns attribute values of different types than described on http://de.php.net/manual/en/ref.pdo.php . PDO::ATTR_CLIENT_VERSION documented : integer actual type returned: string tested with : sqlite, mysql, pgsql suggestion : for BC reasons no change, document it PDO::ATTR_PERSISTENT documented : integer actual type returned : boolean tested with : sqlite, mysql, pgsql suggestion : I have no preference myself PDO::ATTR_SERVER_VERSION documented : integer actual type returned : string tested with : sqlite, mysql, pgsql suggestion : for BC reasons no change, document it PDO::ATTR_STATEMENT_CLASS documented : integer actual type returned : array tested with : sqlite, mysql, pgsql suggestion : update the manual to array I guess it does not matter what driver you use. For example the type setting for PDO::ATTR_PERSISTENT/PDO::ATTR_STATEMENT_CLASS happens in ext/pdo/pdo_dbh.c . However, my point is that the manual and what you actually find differs. Get it in sync and I'm fine. Reproduce code: --------------- ---------------PDO::ATTR_CLIENT_VERSION -------------- [EMAIL PROTECTED]:~/php53> sapi/cli/php -r '$pdo=new PDO("sqlite:/tmp/foo.db"); var_dump($pdo->getAttribute(PDO::ATTR_CLIENT_VERSION));' string(6) "3.3.17" [EMAIL PROTECTED]:~/php53> sapi/cli/php -r '$pdo=new PDO("pgsql:host=localhost port=5432 dbname=phptest user=postgres password="); var_dump($pdo->getAttribute(PDO::ATTR_CLIENT_VERSION));' string(5) "8.2.4" [EMAIL PROTECTED]:~/php53> sapi/cli/php -r '$pdo=new PDO("mysql:dbname=phptest;unix_socket=/tmp/mysql.sock", "root", "root"); var_dump($pdo->getAttribute(PDO::ATTR_CLIENT_VERSION));' string(9) "5.1.24-rc" -------------------- PDO::ATTR_PERSISTENT ----------------- [EMAIL PROTECTED]:~/php53> sapi/cli/php -r '$pdo=new PDO("pgsql:host=localhost port=5432 dbname=phptest user=postgres password="); var_dump($pdo->getAttribute(PDO::ATTR_PERSISTENT));' bool(false) [EMAIL PROTECTED]:~/php53> sapi/cli/php -r '$pdo=new PDO("mysql:dbname=phptest;unix_socket=/tmp/mysql.sock", "root", "root"); var_dump($pdo->getAttribute(PDO::ATTR_PERSISTENT));' bool(false) [EMAIL PROTECTED]:~/php53> sapi/cli/php -r '$pdo=new PDO("sqlite:/tmp/foo.db"); var_dump($pdo->getAttribute(PDO::ATTR_PERSISTENT));' bool(false) --------------------------- PDO::ATTR_STATEMENT_CLASS -------------- [EMAIL PROTECTED]:~/php53> sapi/cli/php -r '$pdo=new PDO("pgsql:host=localhost port=5432 dbname=phptest user=postgres password="); var_dump($pdo->getAttribute(PDO::ATTR_STATEMENT_CLASS));' array(1) { [0]=> string(12) "PDOStatement" } ---------------------- stripped version of my internal test ---------- --TEST-- PDO Common: PDO->getAttribute() --SKIPIF-- <?php # vim:ft=php if (!extension_loaded('pdo')) die('skip'); $dir = getenv('REDIR_TEST_DIR'); if (false == $dir) die('skip no driver'); require_once $dir . 'pdo_test.inc'; PDOTest::skip(); ?> --FILE-- <?php if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE__) . '/../../pdo/tests/'); require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; $db = PDOTest::factory(); function find_invalid_int($valid_options) { do { $invalid = mt_rand(-10000, 10000); } while (in_array($invalid, $valid_options)); return $invalid; } function set_and_get($offset, $db, $attribute, $value, $quiet = false) { $value_type = gettype($value); try { if ([EMAIL PROTECTED]>setAttribute($attribute, $value)) { if (!$quiet) printf("[%03d] Cannot set attribute '%s' to value '%s'\n", $offset, $attribute, var_export($value, true)); return false; } if (gettype($value) != $value_type) { printf("[%03d] Call to PDO::setAttribute(int attribute, mixed value) has changed the type of value from %s to %s, test will not work properly\n", $offset, $value_type, gettype($value)); return false; } $tmp = $db->getAttribute($attribute); if ($tmp !== $value) { if (!$quiet) printf("[%03d] Attribute '%s' was set to '%s' but getAttribute() reports '%s'\n", $offset, $attribute, var_export($value, true), var_export($tmp, true)); return false; } } catch (PDOException $e) { printf("[%03d] %s, [%s] %s\n", $offset, $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); return false; } return true; } $attributes = array( 'PDO::ATTR_CASE' => array( 'const' => PDO::ATTR_CASE, 'type_manual' => 'integer', 'type_code' => 'integer', ), 'PDO::ATTR_CLIENT_VERSION' => array( 'const' => PDO::ATTR_CLIENT_VERSION, 'type_manual' => 'integer', 'type_code' => null, ), 'PDO::ATTR_DRIVER_NAME' => array( 'const' => PDO::ATTR_DRIVER_NAME, 'type_manual' => 'string', 'type_code' => 'string', ), 'PDO::ATTR_ERRMODE' => array( 'const' => PDO::ATTR_ERRMODE, 'type_manual' => 'integer', 'type_code' => 'integer', ), 'PDO::ATTR_ORACLE_NULLS' => array( 'const' => PDO::ATTR_ORACLE_NULLS, 'type_manual' => 'integer', 'type_code' => 'integer', ), 'PDO::ATTR_PERSISTENT' => array( 'const' => PDO::ATTR_PERSISTENT, 'type_manual' => 'integer', 'type_code' => 'boolean', ), 'PDO::ATTR_SERVER_VERSION' => array( 'const' => PDO::ATTR_SERVER_VERSION, 'type_manual' => 'integer', 'type_code' => null, ), 'PDO::ATTR_STATEMENT_CLASS' => array( 'const' => PDO::ATTR_STATEMENT_CLASS, 'type_manual' => 'integer', 'type_code' => 'array', ), ); if (version_compare(PHP_VERSION, '5.2.0', '>=')) $attributes['PDO::ATTR_DEFAULT_FETCH_MODE'] = array( 'const' => PDO::ATTR_DEFAULT_FETCH_MODE, 'type_manual' => 'integer', 'type_code' => 'integer', ); try { foreach ($attributes as $name => $attribute) { printf("PDO::getAttribute(%s)\n", $name); $setting = $db->getAttribute($attribute['const']); $type = gettype($setting); switch ($type) { case 'int': $type = 'integer'; break; case 'bool': $type = 'boolean'; break; default: break; } if ($type != $attribute['type_manual']) { printf("[005] According to the manual PDO::getAttribute(%s) should return a value of type '%s' found type '%s'\n", $name, $attribute['type_manual'], $type); } if (!is_null($attribute['type_code']) && ($type != $attribute['type_code'])) { printf("[006] According to the code PDO::getAttribute(%s) should return a value of type '%s' found type '%s'\n", $name, $attribute['type_code'], $type); } } } catch (PDOException $e) { printf("[007] %s, [%s} %s\n", $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo())); } set_and_get(8, $db, PDO::ATTR_CASE, PDO::CASE_LOWER); set_and_get(9, $db, PDO::ATTR_CASE, PDO::CASE_NATURAL); set_and_get(10, $db, PDO::ATTR_CASE, PDO::CASE_UPPER); set_and_get(11, $db, PDO::ATTR_CASE, find_invalid_int(array(PDO::CASE_LOWER, PDO::CASE_NATURAL. PDO::CASE_UPPER))); set_and_get(12, $db, PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); set_and_get(13, $db, PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); set_and_get(14, $db, PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // back to what we use for testing... set_and_get(15, $db, PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); set_and_get(16, $db, PDO::ATTR_ERRMODE, find_invalid_int(array(PDO::ERRMODE_SILENT, PDO::ERRMODE_WARNING, PDO::ERRMODE_EXCEPTION))); set_and_get(17, $db, PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL); set_and_get(18, $db, PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); set_and_get(19, $db, PDO::ATTR_ORACLE_NULLS, PDO::NULL_TO_STRING); class MyPDOStatement extends PDOStatement { private function __construct() { parent::__construct(); } } set_and_get(21, $db, PDO::ATTR_STATEMENT_CLASS, array('MyPDOStatement', array())); print "done!"; ?> --EXPECTF-- PDO::getAttribute(PDO::ATTR_CASE) PDO::getAttribute(PDO::ATTR_CLIENT_VERSION) PDO::getAttribute(PDO::ATTR_DRIVER_NAME) PDO::getAttribute(PDO::ATTR_ERRMODE) PDO::getAttribute(PDO::ATTR_ORACLE_NULLS) PDO::getAttribute(PDO::ATTR_PERSISTENT) PDO::getAttribute(PDO::ATTR_SERVER_VERSION) PDO::getAttribute(PDO::ATTR_STATEMENT_CLASS) PDO::getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE) [011] Cannot set attribute '%s' to value '%s' [016] Cannot set attribute '%s' to value '%s' done! Expected result: ---------------- See above Actual result: -------------- See above -- Edit bug report at http://bugs.php.net/?id=44158&edit=1 -- Try a CVS snapshot (PHP 5.2): http://bugs.php.net/fix.php?id=44158&r=trysnapshot52 Try a CVS snapshot (PHP 5.3): http://bugs.php.net/fix.php?id=44158&r=trysnapshot53 Try a CVS snapshot (PHP 6.0): http://bugs.php.net/fix.php?id=44158&r=trysnapshot60 Fixed in CVS: http://bugs.php.net/fix.php?id=44158&r=fixedcvs Fixed in release: http://bugs.php.net/fix.php?id=44158&r=alreadyfixed Need backtrace: http://bugs.php.net/fix.php?id=44158&r=needtrace Need Reproduce Script: http://bugs.php.net/fix.php?id=44158&r=needscript Try newer version: http://bugs.php.net/fix.php?id=44158&r=oldversion Not developer issue: http://bugs.php.net/fix.php?id=44158&r=support Expected behavior: http://bugs.php.net/fix.php?id=44158&r=notwrong Not enough info: http://bugs.php.net/fix.php?id=44158&r=notenoughinfo Submitted twice: http://bugs.php.net/fix.php?id=44158&r=submittedtwice register_globals: http://bugs.php.net/fix.php?id=44158&r=globals PHP 4 support discontinued: http://bugs.php.net/fix.php?id=44158&r=php4 Daylight Savings: http://bugs.php.net/fix.php?id=44158&r=dst IIS Stability: http://bugs.php.net/fix.php?id=44158&r=isapi Install GNU Sed: http://bugs.php.net/fix.php?id=44158&r=gnused Floating point limitations: http://bugs.php.net/fix.php?id=44158&r=float No Zend Extensions: http://bugs.php.net/fix.php?id=44158&r=nozend MySQL Configuration Error: http://bugs.php.net/fix.php?id=44158&r=mysqlcfg