cvs: php-src /ext/pdo_odbc odbc_stmt.c /ext/pdo_odbc/tests long_columns.phpt
| From: | Wez Furlong | Date: | Tue, 19 Jul 2005 15:26:16 +0000 |
| Subject: | cvs: php-src /ext/pdo_odbc odbc_stmt.c /ext/pdo_odbc/tests long_columns.phpt | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-32989@lists.php.net to get a copy of this message | ||
wez Tue Jul 19 11:26:16 2005 EDT
Added files:
/php-src/ext/pdo_odbc/tests long_columns.phpt
Modified files:
/php-src/ext/pdo_odbc odbc_stmt.c
Log:
Closes #33533 by implementing proper dynamic fetching of long text columns.
http://cvs.php.net/diff.php/php-src/ext/pdo_odbc/odbc_stmt.c?r1=1.24&r2=1.25&ty=u
Index: php-src/ext/pdo_odbc/odbc_stmt.c
diff -u php-src/ext/pdo_odbc/odbc_stmt.c:1.24 php-src/ext/pdo_odbc/odbc_stmt.c:1.25
--- php-src/ext/pdo_odbc/odbc_stmt.c:1.24 Mon Jul 18 23:39:49 2005
+++ php-src/ext/pdo_odbc/odbc_stmt.c Tue Jul 19 11:26:15 2005
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: odbc_stmt.c,v 1.24 2005/07/19 03:39:49 wez Exp $ */
+/* $Id: odbc_stmt.c,v 1.25 2005/07/19 15:26:15 wez Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -386,28 +386,29 @@
return 0;
}
- /* enforce a practical limitation.
- * TODO: make this work more nicely */
- if (colsize > 65535) {
- colsize = 65535;
- }
-
col->maxlen = S->cols[colno].datalen = colsize;
col->namelen = colnamelen;
col->name = estrdup(S->cols[colno].colname);
- S->cols[colno].data = emalloc(colsize+1);
-
/* returning data as a string */
col->param_type = PDO_PARAM_STR;
- /* tell ODBC to put it straight into our buffer */
- rc = SQLBindCol(S->stmt, colno+1, SQL_C_CHAR, S->cols[colno].data,
+ /* tell ODBC to put it straight into our buffer, but only if it
+ * isn't "long" data */
+ if (colsize < 256) {
+ S->cols[colno].data = emalloc(colsize+1);
+
+ rc = SQLBindCol(S->stmt, colno+1, SQL_C_CHAR, S->cols[colno].data,
S->cols[colno].datalen+1, &S->cols[colno].fetched_len);
- if (rc != SQL_SUCCESS) {
- pdo_odbc_stmt_error("SQLBindCol");
- return 0;
+ if (rc != SQL_SUCCESS) {
+ pdo_odbc_stmt_error("SQLBindCol");
+ return 0;
+ }
+ } else {
+ /* allocate a smaller buffer to keep around for smaller
+ * "long" columns */
+ S->cols[colno].data = emalloc(256);
}
return 1;
@@ -418,6 +419,80 @@
pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data;
pdo_odbc_column *C = &S->cols[colno];
+ /* if it is a column containing "long" data, perform late binding now */
+ if (C->datalen > 255) {
+ unsigned long alloced = 4096;
+ unsigned long used = 0;
+ char *buf;
+ RETCODE rc;
+
+ /* fetch it into C->data, which is allocated with a length
+ * of 256 bytes; if there is more to be had, we then allocate
+ * bigger buffer for the caller to free */
+
+ rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR, C->data,
+ 256, &C->fetched_len);
+
+ if (rc == SQL_SUCCESS) {
+ /* all the data fit into our little buffer;
+ * jump down to the generic bound data case */
+ goto in_data;
+ }
+
+ if (rc == SQL_SUCCESS_WITH_INFO) {
+ /* promote up to a bigger buffer */
+
+ if (C->fetched_len != SQL_NO_TOTAL) {
+ /* use size suggested by the driver, if it knows it */
+ alloced = C->fetched_len + 1;
+ }
+
+ buf = emalloc(alloced);
+ memcpy(buf, C->data, 256);
+ used = 255; /* not 256; the driver NUL terminated the buffer */
+
+ do {
+ C->fetched_len = 0;
+ rc = SQLGetData(S->stmt, colno+1, SQL_C_CHAR,
+ buf + used, alloced - used,
+ &C->fetched_len);
+
+ if (rc == SQL_NO_DATA) {
+ /* we got the lot */
+ break;
+ }
+
+ if (C->fetched_len == SQL_NO_TOTAL) {
+ used += alloced - used;
+ } else {
+ used += C->fetched_len;
+ }
+
+ /* we need to fetch another chunk; resize the
+ * buffer */
+ alloced *= 2;
+ buf = erealloc(buf, alloced);
+ } while (1);
+
+ /* size down */
+ if (used < alloced - 1024) {
+ alloced = used+1;
+ buf = erealloc(buf, used+1);
+ }
+ buf[used] = '\0';
+ *ptr = buf;
+ *caller_frees = 1;
+ *len = used;
+ return 1;
+ }
+
+ /* something went caca */
+ *ptr = NULL;
+ *len = 0;
+ return 1;
+ }
+
+in_data:
/* check the indicator to ensure that the data is intact */
if (C->fetched_len == SQL_NULL_DATA) {
/* A NULL value */
http://cvs.php.net/co.php/php-src/ext/pdo_odbc/tests/long_columns.phpt?r=1.1&p=1
Index: php-src/ext/pdo_odbc/tests/long_columns.phpt
+++ php-src/ext/pdo_odbc/tests/long_columns.phpt
--TEST--
PDO ODBC "long" columns
--SKIPIF--
<?php # vim:ft=php
if (!extension_loaded('pdo_odbc')) print 'skip not loaded';
?>
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_odbc/tests/common.phpt');
$db->exec('CREATE TABLE TEST (id INT NOT NULL PRIMARY KEY, data longtext)');
$sizes = array(32, 64, 128, 253, 254, 255, 256, 257, 258, 512, 1024, 2048, 3998, 3999, 4000);
$db->beginTransaction();
$insert = $db->prepare('INSERT INTO TEST VALUES (?, ?)');
foreach ($sizes as $num) {
$insert->execute(array($num, str_repeat('i', $num)));
}
$db->Commit();
$insert = null;
foreach ($db->query('SELECT id, data from TEST') as $row) {
$expect = str_repeat('i', $row[0]);
if (strcmp($expect, $row[1])) {
echo "Failed on size $row[id]:\n";
printf("Expected %d bytes, got %d\n", strlen($expect), strlen($row['data']));
echo bin2hex($expect) . "\n";
echo bin2hex($row['data']) . "\n";
}
}
echo "Finished\n";
--EXPECT--
Finished