php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #44158 Several PDO attributes are documented with the wrong type
Submitted: 2008-02-18 19:31 UTC Modified: 2008-11-07 11:49 UTC
From: uwendel at mysql dot com Assigned:
Status: Not a bug Package: Documentation problem
PHP Version: 5.3CVS-2008-02-18 (CVS) OS: Linux
Private report: No CVE-ID: None
 [2008-02-18 19:31 UTC] uwendel at mysql dot com
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 --------------

nixnutz@ulflinux:~/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"

nixnutz@ulflinux:~/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"

nixnutz@ulflinux:~/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 -----------------

nixnutz@ulflinux:~/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)

nixnutz@ulflinux:~/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)

nixnutz@ulflinux:~/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 --------------


nixnutz@ulflinux:~/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 (!@$db->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

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-11-07 11:49 UTC] vrana@php.net
You misunderstood the documented type. It documents the type of the constant, not the type of returned value. gettype(PDO::ATTR_CLIENT_VERSION) really returns integer.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Mon Apr 28 00:01:29 2025 UTC