@@ -639,6 +639,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
639
639
640
640
/* if it is a column containing "long" data, perform late binding now */
641
641
if (C -> is_long ) {
642
+ SQLLEN orig_fetched_len = SQL_NULL_DATA ;
642
643
RETCODE rc ;
643
644
644
645
/* fetch it into C->data, which is allocated with a length
@@ -647,6 +648,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
647
648
648
649
rc = SQLGetData (S -> stmt , colno + 1 , C -> is_unicode ? SQL_C_BINARY : SQL_C_CHAR , C -> data ,
649
650
256 , & C -> fetched_len );
651
+ orig_fetched_len = C -> fetched_len ;
650
652
651
653
if (rc == SQL_SUCCESS ) {
652
654
/* all the data fit into our little buffer;
@@ -658,27 +660,35 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
658
660
/* this is a 'long column'
659
661
660
662
read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
661
- in order into the output buffer
663
+ in order into the output buffer; 255 bytes are an optimistic assumption, since the driver may assert
664
+ more or less NUL bytes at the end; we cater to that later, if actual length information is available
662
665
663
666
this loop has to work whether or not SQLGetData() provides the total column length.
664
667
calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
665
668
for that size would be slower except maybe for extremely long columns.*/
666
669
char * buf2 = emalloc (256 );
667
- zend_string * str = zend_string_init (C -> data , 255 , 0 );
670
+ zend_string * str = zend_string_init (C -> data , 256 , 0 );
668
671
size_t used = 255 ; /* not 256; the driver NUL terminated the buffer */
669
672
670
673
do {
671
674
C -> fetched_len = 0 ;
672
675
/* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
673
- rc = SQLGetData (S -> stmt , colno + 1 , SQL_C_CHAR , buf2 , 256 , & C -> fetched_len );
676
+ rc = SQLGetData (S -> stmt , colno + 1 , C -> is_unicode ? SQL_C_BINARY : SQL_C_CHAR , buf2 , 256 , & C -> fetched_len );
677
+
678
+ /* adjust `used` in case we have length info from the driver */
679
+ if (orig_fetched_len >= 0 && C -> fetched_len >= 0 ) {
680
+ SQLLEN fixed_used = orig_fetched_len - C -> fetched_len ;
681
+ ZEND_ASSERT (fixed_used <= used + 1 );
682
+ used = fixed_used ;
683
+ }
674
684
675
685
/* resize output buffer and reassemble block */
676
686
if (rc == SQL_SUCCESS_WITH_INFO ) {
677
687
/* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
678
688
states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
679
689
(if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
680
- str = zend_string_realloc (str , used + 255 , 0 );
681
- memcpy (ZSTR_VAL (str ) + used , buf2 , 255 );
690
+ str = zend_string_realloc (str , used + 256 , 0 );
691
+ memcpy (ZSTR_VAL (str ) + used , buf2 , 256 );
682
692
used = used + 255 ;
683
693
} else if (rc == SQL_SUCCESS ) {
684
694
str = zend_string_realloc (str , used + C -> fetched_len , 0 );
0 commit comments