Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed the error in Issue 570 #952

Merged
merged 4 commits into from
Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion source/shared/core_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ size_t sqlsrv_stream_read( _Inout_ php_stream* stream, _Out_writes_bytes_(count)
break;
}

SQLRETURN r = SQLGetData( ss->stmt->handle(), ss->field_index + 1, c_type, get_data_buffer, count /*BufferLength*/, &read );
// Warnings will be handled below
SQLRETURN r = ss->stmt->current_results->get_data(ss->field_index + 1, c_type, get_data_buffer, count /*BufferLength*/, &read, false /*handle_warning*/ TSRMLS_CC);

CHECK_SQL_ERROR( r, ss->stmt ) {
stream->eof = 1;
Expand Down
143 changes: 143 additions & 0 deletions test/functional/sqlsrv/srv_570_fetch_varbinary.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
--TEST--
GitHub issue #570 - fetching a varbinary field as a stream using client buffer
--DESCRIPTION--
Verifies that a varbinary field (with size or max) can be successfully fetched even when a client buffer is used. There is no more "Invalid cursor state" error.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php

function compareStreams($input, $result)
{
while (($line1 = fread($input, 80)) && ($line2 = fread($result, 80))) {
if ($line1 != $line2) {
echo "Stream not identical\n";
break;
}
}
}

function fetchData($stmt, $data, $buffered)
{
if ($buffered) {
$result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_FIRST);
} else {
$result = sqlsrv_fetch($stmt);
}
if ($result === false) {
fatalError('Error when fetching data');
}

// Get image data as a binary stream
$image = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
if ($image === false) {
fatalError('Error in calling sqlsrv_get_field');
}

// Does the retrieved stream match with the original?
compareStreams($data, $image);

fclose($image);
}

function runQuery($conn, $data, $tsql, $buffered, $prepared)
{
if ($prepared) {
if ($buffered) {
// Pick a random size for the buffer large enough for this test
$stmt = sqlsrv_prepare($conn, $tsql, array(), array("Scrollable" => SQLSRV_CURSOR_CLIENT_BUFFERED, "ClientBufferMaxKBSize" => 51200));
} else {
$stmt = sqlsrv_prepare($conn, $tsql);
}
if ($stmt === false) {
fatalError("Error in preparing the query ($buffered).");
}

$result = sqlsrv_execute($stmt);
if ($result === false) {
fatalError("Error in executing the query ($buffered).");
}
} else {
if ($buffered) {
// Use the default buffer size in this case
$stmt = sqlsrv_query($conn, $tsql, array(), array("Scrollable"=>SQLSRV_CURSOR_CLIENT_BUFFERED));
} else {
$stmt = sqlsrv_query($conn, $tsql);
}

if ($stmt === false) {
fatalError("Error in sqlsrv_query ($buffered).");
}
}

fetchData($stmt, $data, $buffered);
}

function runTest($conn, $columnType, $path)
{
$tableName = 'srvTestTable_570' . rand(0, 10);
dropTable($conn, $tableName);

// Create the test table with only one column
$tsql = "CREATE TABLE $tableName([picture] $columnType NOT NULL)";
$stmt = sqlsrv_query($conn, $tsql);
if (!$stmt) {
fatalError("Failed to create table $tableName\n");
}

// Insert php.gif as stream data
$tsql = "INSERT INTO $tableName (picture) VALUES (?)";

$data = fopen($path, 'rb');
if (!$data) {
fatalError('Could not open image for reading.');
}

$params = array($data, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
$stmt = sqlsrv_query($conn, $tsql, array($params));
if ($stmt === false) {
fatalError("Failed to insert image into $tableName");
}
do {
$read = sqlsrv_send_stream_data($stmt);
} while ($read);
sqlsrv_free_stmt($stmt);

// Start testing, with or without client buffer, using prepared statement or direct query
$tsql = "SELECT picture FROM $tableName";
runQuery($conn, $data, $tsql, false, true);
runQuery($conn, $data, $tsql, true, true);
runQuery($conn, $data, $tsql, false, false);
runQuery($conn, $data, $tsql, true, false);

// Clean up
fclose($data);

dropTable($conn, $tableName);
}

require_once('MsCommon.inc');

$conn = connect();
if ($conn === false) {
die(print_r(sqlsrv_errors(), true));
}

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$pic = '\\php.gif';
} else { // other than Windows
$pic = '/php.gif';
}
$path = dirname($_SERVER['PHP_SELF']) . $pic;

runTest($conn, 'VARBINARY(MAX)', $path);
runTest($conn, 'VARBINARY(4096)', $path);

echo "Done\n";

sqlsrv_close($conn);
?>
--EXPECT--
Done