Skip to content

Commit e86b39a

Browse files
committed
Fix GH-9372: HY010 when binding overlong parameter
If `SQLPutData()` *fails*, we should not call `SQLParamData()` again, because that yields the confusing `HY010` (Function sequence error). Instead we properly handle `SQLPutData()` errors. For the given case (paramter length > column length), some drivers let `SQLPutData()` fail, while others do not. Either behavior seems to conform to the ODBC specification. Anyhow, we do not want to silently truncate the given parameter, since that would break the behavior for drivers which do not fail, but still don't simply truncate the given parameter. So it is finally up to userland to avoid passing overlong parameters – with this patch they at least get useful information about the actual issue.
1 parent 2e6b317 commit e86b39a

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

ext/pdo_odbc/odbc_stmt.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ static int odbc_stmt_dtor(pdo_stmt_t *stmt)
155155

156156
static int odbc_stmt_execute(pdo_stmt_t *stmt)
157157
{
158-
RETCODE rc;
158+
RETCODE rc, rc1;
159159
pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
160160
char *buf = NULL;
161161
SQLLEN row_count = -1;
@@ -192,11 +192,17 @@ static int odbc_stmt_execute(pdo_stmt_t *stmt)
192192
Z_STRLEN_P(parameter),
193193
&ulen)) {
194194
case PDO_ODBC_CONV_NOT_REQUIRED:
195-
SQLPutData(S->stmt, Z_STRVAL_P(parameter),
195+
rc1 = SQLPutData(S->stmt, Z_STRVAL_P(parameter),
196196
Z_STRLEN_P(parameter));
197+
if (rc1 != SQL_SUCCESS && rc1 != SQL_SUCCESS_WITH_INFO) {
198+
rc = rc1;
199+
}
197200
break;
198201
case PDO_ODBC_CONV_OK:
199-
SQLPutData(S->stmt, S->convbuf, ulen);
202+
rc1 = SQLPutData(S->stmt, S->convbuf, ulen);
203+
if (rc1 != SQL_SUCCESS && rc1 != SQL_SUCCESS_WITH_INFO) {
204+
rc = rc1;
205+
}
200206
break;
201207
case PDO_ODBC_CONV_FAIL:
202208
pdo_odbc_stmt_error("error converting input string");
@@ -233,7 +239,10 @@ static int odbc_stmt_execute(pdo_stmt_t *stmt)
233239
if (len == 0) {
234240
break;
235241
}
236-
SQLPutData(S->stmt, buf, len);
242+
rc1 = SQLPutData(S->stmt, buf, len);
243+
if (rc1 != SQL_SUCCESS && rc1 != SQL_SUCCESS_WITH_INFO) {
244+
rc = rc1;
245+
}
237246
} while (1);
238247
}
239248
}

ext/pdo_odbc/tests/gh9372.phpt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Bug GH-9372 (HY010 when binding overlong parameter)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('pdo_odbc')) die('skip pdo_odbc extension not available');
6+
require 'ext/pdo/tests/pdo_test.inc';
7+
PDOTest::skip();
8+
?>
9+
--FILE--
10+
<?php
11+
require 'ext/pdo/tests/pdo_test.inc';
12+
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
13+
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
14+
15+
$db->exec("CREATE TABLE gh9372 (col VARCHAR(10))");
16+
$db->exec("INSERT INTO gh9372 VALUES ('something')");
17+
18+
$stmt = $db->prepare("SELECT * FROM bug74186 WHERE col = ?");
19+
$stmt->bindValue(1, 'something else');
20+
try {
21+
$stmt->execute();
22+
} catch (PDOException $ex) {
23+
if ($ex->getCode() !== "22001") {
24+
var_dump($ex->getMessage());
25+
}
26+
}
27+
28+
$stmt = $db->prepare("SELECT * FROM bug74186 WHERE col = ?");
29+
$stream = fopen("php://memory", "w+");
30+
fwrite($stream, 'something else');
31+
rewind($stream);
32+
$stmt->bindvalue(1, $stream, PDO::PARAM_LOB);
33+
try {
34+
$stmt->execute();
35+
} catch (PDOException $ex) {
36+
if ($ex->getCode() !== "22001") {
37+
var_dump($ex->getMessage());
38+
}
39+
}
40+
?>
41+
--CLEAN--
42+
<?php
43+
require 'ext/pdo/tests/pdo_test.inc';
44+
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
45+
$db->exec("DROP TABLE gh9372");
46+
?>
47+
--EXPECT--

0 commit comments

Comments
 (0)