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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: uwendel at mysql dot com
New email:
PHP Version: OS:

 

 [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 08:01:28 2025 UTC