Skip to content

Commit 2aeb53e

Browse files
committed
TypeErrors for invalid attribute options
1 parent 615563b commit 2aeb53e

File tree

4 files changed

+81
-79
lines changed

4 files changed

+81
-79
lines changed

ext/pdo/pdo_dbh.c

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -766,28 +766,26 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
766766
PDO_HANDLE_DBH_ERR();
767767
return FAILURE;
768768
}
769-
if (Z_TYPE_P(value) != IS_ARRAY
770-
|| (item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL
771-
|| Z_TYPE_P(item) != IS_STRING
772-
|| (pce = zend_lookup_class(Z_STR_P(item))) == NULL
773-
) {
774-
/* TODO Always TypeError */
775-
pdo_raise_impl_error(dbh, NULL, "HY000",
776-
"PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
777-
"the classname must be a string specifying an existing class"
778-
);
779-
PDO_HANDLE_DBH_ERR();
769+
if (Z_TYPE_P(value) != IS_ARRAY) {
770+
zend_type_error("PDO::ATTR_STATEMENT_CLASS's value must be of type array, %s given",
771+
zend_zval_type_name(value));
772+
return FAILURE;
773+
}
774+
if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL) {
775+
zend_value_error("PDO::ATTR_STATEMENT_CLASS's value must be an array with the following "
776+
"format array(classname, array(ctor_args))");
777+
return FAILURE;
778+
}
779+
if (Z_TYPE_P(item) != IS_STRING || (pce = zend_lookup_class(Z_STR_P(item))) == NULL) {
780+
zend_type_error("PDO::ATTR_STATEMENT_CLASS's class must be a valid class");
780781
return FAILURE;
781782
}
782783
if (!instanceof_function(pce, pdo_dbstmt_ce)) {
783-
/* TODO Always TypeError */
784-
pdo_raise_impl_error(dbh, NULL, "HY000",
785-
"user-supplied statement class must be derived from PDOStatement");
786-
PDO_HANDLE_DBH_ERR();
784+
zend_type_error("PDO::ATTR_STATEMENT_CLASS's class must be derived from PDOStatement");
787785
return FAILURE;
788786
}
789787
if (pce->constructor && !(pce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
790-
/* TODO Always TypeError */
788+
/* TODO Always Error? */
791789
pdo_raise_impl_error(dbh, NULL, "HY000",
792790
"user-supplied statement class cannot have a public constructor");
793791
PDO_HANDLE_DBH_ERR();
@@ -800,12 +798,8 @@ static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /*
800798
}
801799
if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) {
802800
if (Z_TYPE_P(item) != IS_ARRAY) {
803-
/* TODO Always TypeError */
804-
pdo_raise_impl_error(dbh, NULL, "HY000",
805-
"PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
806-
"ctor_args must be an array"
807-
);
808-
PDO_HANDLE_DBH_ERR();
801+
zend_type_error("PDO::ATTR_STATEMENT_CLASS's ctor_args must be ?array, %s given",
802+
zend_zval_type_name(value));
809803
return FAILURE;
810804
}
811805
ZVAL_COPY(&dbh->def_stmt_ctor_args, item);

ext/pdo/tests/bug_44159.phpt

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
PDO Common: Bug #44159 (Crash: $pdo->setAttribute(PDO::STATEMENT_ATTR_CLASS, NULL))
33
--SKIPIF--
44
<?php
5-
if (!extension_loaded('pdo')) die('skip PDO not available');
6-
try {
7-
$pdo = new PDO("sqlite:".__DIR__."/foo.db");
8-
} catch (Exception $e) {
9-
die("skip PDP_SQLITE not available");
10-
}
5+
if (!extension_loaded('pdo')) die('skip');
6+
$dir = getenv('REDIR_TEST_DIR');
7+
if (false == $dir) die('skip no driver');
8+
require_once $dir . 'pdo_test.inc';
9+
PDOTest::skip();
1110
?>
1211
--FILE--
1312
<?php
14-
$pdo = new PDO("sqlite:".__DIR__."/foo.db");
13+
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
14+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
15+
$pdo = PDOTest::factory();
1516
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
1617

1718
$attrs = array(PDO::ATTR_STATEMENT_CLASS, PDO::ATTR_STRINGIFY_FETCHES, PDO::NULL_TO_STRING);
@@ -37,24 +38,13 @@ foreach ($attrs as $attr) {
3738
@unlink(__DIR__."/foo.db");
3839

3940
?>
40-
--EXPECTF--
41-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
42-
43-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
44-
bool(false)
45-
46-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
47-
48-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
49-
bool(false)
50-
51-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
52-
53-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
54-
bool(false)
41+
--EXPECT--
42+
TypeError: PDO::ATTR_STATEMENT_CLASS's value must be of type array, null given
43+
TypeError: PDO::ATTR_STATEMENT_CLASS's value must be of type array, int given
44+
TypeError: PDO::ATTR_STATEMENT_CLASS's value must be of type array, string given
5545
TypeError: Attribute value must be int for selected attribute, null given
5646
bool(true)
5747
bool(true)
58-
bool(true)
59-
bool(true)
60-
bool(true)
48+
bool(false)
49+
bool(false)
50+
bool(false)

ext/pdo_mysql/tests/pdo_mysql_attr_oracle_nulls.phpt

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,22 @@ MySQLPDOTest::skip();
1212
$db = MySQLPDOTest::factory();
1313
MySQLPDOTest::createTestTable($db);
1414

15-
$tmp = array();
16-
if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, $tmp))
17-
printf("[001] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
18-
19-
$tmp = new stdClass();
20-
if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, $tmp));
21-
printf("[002] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
22-
23-
if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 'pdo'))
24-
printf("[003] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
15+
try {
16+
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, []);
17+
} catch (\TypeError $e) {
18+
echo $e->getMessage(), \PHP_EOL;
19+
}
20+
try {
21+
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, new stdClass());
22+
} catch (\TypeError $e) {
23+
echo $e->getMessage(), \PHP_EOL;
24+
}
25+
try {
26+
/* Currently passes... */
27+
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 'pdo');
28+
} catch (\TypeError $e) {
29+
echo $e->getMessage(), \PHP_EOL;
30+
}
2531

2632
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 1);
2733
$stmt = $db->query("SELECT NULL AS z, '' AS a, ' ' AS b, TRIM(' ') as c, ' d' AS d, '" . chr(0) . " e' AS e");
@@ -82,8 +88,8 @@ MySQLPDOTest::skip();
8288
print "done!";
8389
?>
8490
--EXPECTF--
85-
[002] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...
86-
[003] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...
91+
Attribute value must be int for selected attribute, array given
92+
Attribute value must be int for selected attribute, stdClass given
8793
array(1) {
8894
[0]=>
8995
array(6) {

ext/pdo_mysql/tests/pdo_mysql_attr_statement_class.phpt

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,35 @@ $db = MySQLPDOTest::factory();
1616
$default = $db->getAttribute(PDO::ATTR_STATEMENT_CLASS);
1717
var_dump($default);
1818

19-
if (false !== ($tmp = @$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'foo')))
20-
printf("[002] Expecting boolean/false got %s\n", var_export($tmp, true));
21-
22-
if (false !== ($tmp = @$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('classname'))))
23-
printf("[003] Expecting boolean/false got %s\n", var_export($tmp, true));
24-
19+
try {
20+
$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'foo');
21+
} catch (\TypeError $e) {
22+
echo $e->getMessage(), \PHP_EOL;
23+
}
24+
try {
25+
$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['classname']);
26+
} catch (\TypeError $e) {
27+
echo $e->getMessage(), \PHP_EOL;
28+
}
2529
// unknown class
26-
if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('classname', array()))))
27-
printf("[004] Expecting boolean/false got %s\n", var_export($tmp, true));
30+
try {
31+
$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['classname', []]);
32+
} catch (\TypeError $e) {
33+
echo $e->getMessage(), \PHP_EOL;
34+
}
2835

2936
// class not derived from PDOStatement
3037
class myclass {
3138
function __construct() {
3239
printf("myclass\n");
3340
}
3441
}
35-
if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('myclass', array()))))
36-
printf("[005] Expecting boolean/false got %s\n", var_export($tmp, true));
42+
43+
try {
44+
$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['myclass', []]);
45+
} catch (\TypeError $e) {
46+
echo $e->getMessage(), \PHP_EOL;
47+
}
3748

3849
// public constructor not allowed
3950
class mystatement extends PDOStatement {
@@ -42,8 +53,13 @@ $db = MySQLPDOTest::factory();
4253
}
4354
}
4455

45-
if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement', array()))))
46-
printf("[006] Expecting boolean/false got %s\n", var_export($tmp, true));
56+
try {
57+
if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['mystatement', []])))
58+
printf("[006] Expecting boolean/false got %s\n", var_export($tmp, true));
59+
} catch (\Error $e) {
60+
echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
61+
}
62+
4763

4864
// ... but a public destructor is allowed
4965
class mystatement2 extends PDOStatement {
@@ -109,14 +125,10 @@ array(1) {
109125
[0]=>
110126
string(12) "PDOStatement"
111127
}
112-
113-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
114-
115-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
116-
117-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: user-supplied statement class must be derived from PDOStatement in %s on line %d
118-
119-
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
128+
PDO::ATTR_STATEMENT_CLASS's value must be of type array, string given
129+
PDO::ATTR_STATEMENT_CLASS's class must be a valid class
130+
PDO::ATTR_STATEMENT_CLASS's class must be a valid class
131+
PDO::ATTR_STATEMENT_CLASS's class must be derived from PDOStatement
120132

121133
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: user-supplied statement class cannot have a public constructor in %s on line %d
122134

0 commit comments

Comments
 (0)