cvs: php-src /ext/pdo_odbc odbc_stmt.c /ext/pdo_odbc/tests long_columns.phpt

From: 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

« previous php.cvs (#32989) next »