@@ -671,23 +671,29 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
671
671
}
672
672
673
673
if (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS ) {
674
- /* this is a 'long column'
675
-
676
- read the column in 255 byte blocks until the end of the column is reached, reassembling those blocks
677
- in order into the output buffer; 255 bytes are an optimistic assumption, since the driver may assert
678
- more or less NUL bytes at the end; we cater to that later, if actual length information is available
679
-
680
- this loop has to work whether or not SQLGetData() provides the total column length.
681
- calling SQLDescribeCol() or other, specifically to get the column length, then doing a single read
682
- for that size would be slower except maybe for extremely long columns.*/
683
- char * buf2 = emalloc (256 );
684
- zend_string * str = zend_string_init (C -> data , 256 , 0 );
685
- size_t used = 255 ; /* not 256; the driver NUL terminated the buffer */
674
+ /*
675
+ * This is a long column.
676
+ *
677
+ * Try to get as much as we can at once. If the
678
+ * driver somehow has more for us, get more. We'll
679
+ * assemble it into one big buffer at the end.
680
+ *
681
+ * N.B. with n and n+1 mentioned in the comments:
682
+ * n is the size returned without null terminator.
683
+ *
684
+ * The extension previously tried getting it in 256
685
+ * byte blocks, but this could have created trouble
686
+ * with some drivers.
687
+ */
688
+ SQLLEN to_fetch_len = orig_fetched_len + 1 ; /* for 0 at end */
689
+ char * buf2 = emalloc (to_fetch_len );
690
+ zend_string * str = zend_string_init (C -> data , to_fetch_len , 0 );
691
+ size_t used = orig_fetched_len ; /* not n + 1; the driver NUL terminated the buffer */
686
692
687
693
do {
688
694
C -> fetched_len = 0 ;
689
- /* read block. 256 bytes => 255 bytes are actually read, the last 1 is NULL */
690
- rc = SQLGetData (S -> stmt , colno + 1 , C -> is_unicode ? SQL_C_BINARY : SQL_C_CHAR , buf2 , 256 , & C -> fetched_len );
695
+ /* read block. n + 1 bytes => n bytes are actually read, the last 1 is NULL */
696
+ rc = SQLGetData (S -> stmt , colno + 1 , C -> is_unicode ? SQL_C_BINARY : SQL_C_CHAR , buf2 , to_fetch_len , & C -> fetched_len );
691
697
692
698
/* adjust `used` in case we have length info from the driver */
693
699
if (orig_fetched_len >= 0 && C -> fetched_len >= 0 ) {
@@ -697,13 +703,13 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
697
703
}
698
704
699
705
/* resize output buffer and reassemble block */
700
- if (rc == SQL_SUCCESS_WITH_INFO || (rc == SQL_SUCCESS && C -> fetched_len > 255 )) {
706
+ if (rc == SQL_SUCCESS_WITH_INFO || (rc == SQL_SUCCESS && C -> fetched_len > orig_fetched_len )) {
701
707
/* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
702
- states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > 255 (greater than buf2's size)
703
- (if a driver fails to follow that and wrote less than 255 bytes to buf2, this will AV or read garbage into buf) */
704
- str = zend_string_realloc (str , used + 256 , 0 );
705
- memcpy (ZSTR_VAL (str ) + used , buf2 , 256 );
706
- used = used + 255 ;
708
+ states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > n (greater than buf2's size)
709
+ (if a driver fails to follow that and wrote less than n bytes to buf2, this will AV or read garbage into buf) */
710
+ str = zend_string_realloc (str , used + to_fetch_len , 0 );
711
+ memcpy (ZSTR_VAL (str ) + used , buf2 , to_fetch_len );
712
+ used = used + orig_fetched_len ;
707
713
} else if (rc == SQL_SUCCESS ) {
708
714
str = zend_string_realloc (str , used + C -> fetched_len , 0 );
709
715
memcpy (ZSTR_VAL (str ) + used , buf2 , C -> fetched_len );
0 commit comments