@@ -615,7 +615,7 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno)
615615 /* tell ODBC to put it straight into our buffer, but only if it
616616 * isn't "long" data, and only if we haven't already bound a long
617617 * column. */
618- if (colsize < 256 && !S -> going_long ) {
618+ if (colsize < 2048 && !S -> going_long ) {
619619 S -> cols [colno ].data = emalloc (colsize + 1 );
620620 S -> cols [colno ].is_long = 0 ;
621621
@@ -631,7 +631,7 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno)
631631 } else {
632632 /* allocate a smaller buffer to keep around for smaller
633633 * "long" columns */
634- S -> cols [colno ].data = emalloc (256 );
634+ S -> cols [colno ].data = emalloc (2048 );
635635 S -> going_long = 1 ;
636636 S -> cols [colno ].is_long = 1 ;
637637 }
@@ -657,14 +657,14 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
657657 RETCODE rc ;
658658
659659 /* fetch it into C->data, which is allocated with a length
660- * of 256 bytes; if there is more to be had, we then allocate
660+ * of 2048 bytes; if there is more to be had, we then allocate
661661 * bigger buffer for the caller to free */
662662
663663 rc = SQLGetData (S -> stmt , colno + 1 , C -> is_unicode ? SQL_C_BINARY : SQL_C_CHAR , C -> data ,
664- 256 , & C -> fetched_len );
664+ 2048 , & C -> fetched_len );
665665 orig_fetched_len = C -> fetched_len ;
666666
667- if (rc == SQL_SUCCESS && C -> fetched_len < 256 ) {
667+ if (rc == SQL_SUCCESS && C -> fetched_len < 2048 ) {
668668 /* all the data fit into our little buffer;
669669 * jump down to the generic bound data case */
670670 goto in_data ;
@@ -684,16 +684,29 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
684684 * The extension previously tried getting it in 256
685685 * byte blocks, but this could have created trouble
686686 * with some drivers.
687+ *
688+ * However, depending on the driver, fetched_len may
689+ * not contain the number of bytes and SQL_NO_TOTAL
690+ * may be passed.
691+ * The behavior in this case is the same as before,
692+ * dividing the data into blocks. However, it has been
693+ * changed from 256 byte to 2048 byte block.
687694 */
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 */
695+ ssize_t to_fetch_len ;
696+ if (orig_fetched_len == SQL_NO_TOTAL ) {
697+ to_fetch_len = C -> datalen > 2047 ? 2047 : C -> datalen ;
698+ } else {
699+ to_fetch_len = orig_fetched_len ;
700+ }
701+ ssize_t to_fetch_byte = to_fetch_len + 1 ;
702+ char * buf2 = emalloc (to_fetch_byte );
703+ zend_string * str = zend_string_init (C -> data , to_fetch_byte , 0 );
704+ size_t used = to_fetch_len ;
692705
693706 do {
694707 C -> fetched_len = 0 ;
695708 /* 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 );
709+ rc = SQLGetData (S -> stmt , colno + 1 , C -> is_unicode ? SQL_C_BINARY : SQL_C_CHAR , buf2 , to_fetch_byte , & C -> fetched_len );
697710
698711 /* adjust `used` in case we have length info from the driver */
699712 if (orig_fetched_len >= 0 && C -> fetched_len >= 0 ) {
@@ -703,13 +716,13 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
703716 }
704717
705718 /* resize output buffer and reassemble block */
706- if (rc == SQL_SUCCESS_WITH_INFO || (rc == SQL_SUCCESS && C -> fetched_len > orig_fetched_len )) {
719+ if (rc == SQL_SUCCESS_WITH_INFO || (rc == SQL_SUCCESS && C -> fetched_len > to_fetch_len )) {
707720 /* point 5, in section "Retrieving Data with SQLGetData" in http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
708721 states that if SQL_SUCCESS_WITH_INFO, fetched_len will be > n (greater than buf2's size)
709722 (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 ;
723+ str = zend_string_realloc (str , used + to_fetch_byte , 0 );
724+ memcpy (ZSTR_VAL (str ) + used , buf2 , to_fetch_byte );
725+ used = used + to_fetch_len ;
713726 } else if (rc == SQL_SUCCESS ) {
714727 str = zend_string_realloc (str , used + C -> fetched_len , 0 );
715728 memcpy (ZSTR_VAL (str ) + used , buf2 , C -> fetched_len );
0 commit comments