From 44dab5a37859ff9ab54ffb654d58c0491fd57b87 Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Mon, 19 Oct 2020 17:17:23 -0700 Subject: [PATCH] Fixed a bug in reading varbinary max fields --- source/shared/core_results.cpp | 2 +- .../pdo_sqlsrv/pdo_fetch_large_stream.phpt | 155 ++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt diff --git a/source/shared/core_results.cpp b/source/shared/core_results.cpp index 88d3bbd0..1d22be94 100644 --- a/source/shared/core_results.cpp +++ b/source/shared/core_results.cpp @@ -919,7 +919,7 @@ SQLRETURN binary_to_string( _Inout_ SQLCHAR* field_data, _Inout_ SQLLEN& read_so if( to_copy > 0 ) { // quick hex conversion routine Char* h = reinterpret_cast( buffer ); - BYTE* b = reinterpret_cast( field_data ); + BYTE* b = reinterpret_cast( field_data + read_so_far ); // to_copy contains the number of bytes to copy, so we divide the number in half (or quarter) // to get the number of hex digits we can copy SQLLEN to_copy_hex = to_copy / (2 * extra); diff --git a/test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt b/test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt new file mode 100644 index 00000000..270c3fcc --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt @@ -0,0 +1,155 @@ +--TEST-- +Test fetching varbinary, varchar, nvarchar max fields with client buffer +--DESCRIPTION-- +Similar to sqlsrv_fetch_large_stream test but with varbinary, varchar, nvarchar using client buffer +--SKIPIF-- + +--ENV-- +PHPT_EXEC=true +--FILE-- + 1)) { + $success = false; + } + + return ($success); +} + +function fetchBinary($conn, $buffered) +{ + global $tableName, $binaryColumn, $binaryValue, $hexValue; + + try { + $query = "SELECT $binaryColumn FROM $tableName"; + if ($buffered) { + $stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED)); + } else { + $stmt = $conn->prepare($query); + } + $stmt->bindColumn($binaryColumn, $value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + $stmt->execute(); + + $row = $stmt->fetch(PDO::FETCH_BOUND); + + if (!checkData($value, $binaryValue)) { + echo "Fetched binary value unexpected ($buffered): $value\n"; + } + + $stmt->bindColumn($binaryColumn, $value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_SYSTEM); + $stmt->execute(); + + $row = $stmt->fetch(PDO::FETCH_BOUND); + + if (!checkData($value, $hexValue)) { + echo "Fetched binary value a char string ($buffered): $value\n"; + } + + $stmt->bindColumn($binaryColumn, $value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_UTF8); + $stmt->execute(); + + $row = $stmt->fetch(PDO::FETCH_BOUND); + + if (!checkData($value, $hexValue)) { + echo "Fetched binary value as UTF-8 string ($buffered): $value\n"; + var_dump($hexValue); + var_dump($value); + } + } catch (PdoException $e) { + echo "Caught exception in fetchBinary ($buffered):\n"; + echo $e->getMessage() . PHP_EOL; + } +} + +function fetchAsString($conn, $buffered) +{ + global $tableName, $strColumn, $strValue; + global $nstrColumn, $nstrValue; + + try { + $query = "SELECT $strColumn, $nstrColumn FROM $tableName"; + if ($buffered) { + $stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED)); + } else { + $stmt = $conn->prepare($query); + } + $stmt->execute(); + + $stmt->bindColumn($strColumn, $value1, PDO::PARAM_STR); + $stmt->bindColumn($nstrColumn, $value2, PDO::PARAM_STR); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + if (!checkData($value1, $strValue)) { + echo "Fetched string value: $value1\n"; + } + + if (!checkData($value2, $nstrValue)) { + echo "Fetched string value: $value2\n"; + } + $stmt->execute(); + + $stmt->bindColumn($strColumn, $value, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + if (!checkData($value, $strValue)) { + echo "Fetched string value: $value\n"; + } + } catch (PdoException $e) { + echo "Caught exception in fetchBinary ($buffered):\n"; + echo $e->getMessage() . PHP_EOL; + } +} + +try { + $conn = connect(); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Create table of one max column + $colMeta = array(new ColumnMeta('varbinary(max)', $binaryColumn), + new ColumnMeta('varchar(max)', $strColumn), + new ColumnMeta('nvarchar(max)', $nstrColumn)); + createTable($conn, $tableName, $colMeta); + + // Insert one row + $query = "INSERT INTO $tableName ($binaryColumn, $strColumn, $nstrColumn) VALUES (?, ?, ?)"; + $stmt = $conn->prepare($query); + $stmt->bindParam(1, $binaryValue, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + $stmt->bindParam(2, $strValue, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM); + $stmt->bindParam(3, $nstrValue, PDO::PARAM_STR); + $stmt->execute(); + unset($stmt); + + // Starting fetching with or without client buffer + fetchBinary($conn, false); + fetchBinary($conn, true); + + fetchAsString($conn, false); + fetchAsString($conn, true); + + // dropTable($conn, $tableName); + echo "Done\n"; + unset($conn); +} catch (PdoException $e) { + echo $e->getMessage() . PHP_EOL; +} +?> +--EXPECT-- +Done \ No newline at end of file