Skip to content

Commit 57ea0b5

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 559da52 commit 57ea0b5

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
@@ -158,7 +158,7 @@ static int odbc_stmt_dtor(pdo_stmt_t *stmt)
158158

159159
static int odbc_stmt_execute(pdo_stmt_t *stmt)
160160
{
161-
RETCODE rc;
161+
RETCODE rc, rc1;
162162
pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
163163
char *buf = NULL;
164164
SQLLEN row_count = -1;
@@ -195,11 +195,17 @@ static int odbc_stmt_execute(pdo_stmt_t *stmt)
195195
Z_STRLEN_P(parameter),
196196
&ulen)) {
197197
case PDO_ODBC_CONV_NOT_REQUIRED:
198-
SQLPutData(S->stmt, Z_STRVAL_P(parameter),
198+
rc1 = SQLPutData(S->stmt, Z_STRVAL_P(parameter),
199199
Z_STRLEN_P(parameter));
200+
if (rc1 != SQL_SUCCESS && rc1 != SQL_SUCCESS_WITH_INFO) {
201+
rc = rc1;
202+
}
200203
break;
201204
case PDO_ODBC_CONV_OK:
202-
SQLPutData(S->stmt, S->convbuf, ulen);
205+
rc1 = SQLPutData(S->stmt, S->convbuf, ulen);
206+
if (rc1 != SQL_SUCCESS && rc1 != SQL_SUCCESS_WITH_INFO) {
207+
rc = rc1;
208+
}
203209
break;
204210
case PDO_ODBC_CONV_FAIL:
205211
pdo_odbc_stmt_error("error converting input string");
@@ -236,7 +242,10 @@ static int odbc_stmt_execute(pdo_stmt_t *stmt)
236242
if (len == 0) {
237243
break;
238244
}
239-
SQLPutData(S->stmt, buf, len);
245+
rc1 = SQLPutData(S->stmt, buf, len);
246+
if (rc1 != SQL_SUCCESS && rc1 != SQL_SUCCESS_WITH_INFO) {
247+
rc = rc1;
248+
}
240249
} while (1);
241250
}
242251
}

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)