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

Binary stream returned from a statement becomes invalid if the statement gets implicitly closed #1443

Open
morozov opened this issue Feb 27, 2023 · 3 comments

Comments

@morozov
Copy link
Contributor

morozov commented Feb 27, 2023

PHP version
8.2.3

PHP SQLSRV or PDO_SQLSRV version
5.10.1

Microsoft ODBC Driver version
2.3.11

SQL Server version
15.00.4236

Client operating system
macOS

Problem description
If a function prepares and executes a statement that returns an sqlsrv_stream, then the stream becomes invalid outside of the function.

Expected behavior
The stream is valid as long as it has at least one reference.

Actual behavior
The stream is invalid. Passing it to any stream function results in the following error message:

TypeError: supplied resource is not a valid stream resource

Additionally, instead of "sqlsrv_stream", Xdebug displays the stream type as "Unknown".

Repro code or steps to reproduce

function get_stream($conn) {
    $stmt = sqlsrv_query($conn, "SELECT CONVERT(VARBINARY, '0x41')");

    sqlsrv_fetch($stmt);

    return sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
}

$conn = sqlsrv_connect('127.0.0.1', [
    'UID' => 'sa',
    'PWD' => 'Passw0rd',
]);

$stream = get_stream($conn);

var_dump(stream_get_meta_data($stream));

Inlining the code of the get_stream function mitigates the problem.

@morozov morozov changed the title Binary stream returned from a statement becomes inaccessible if the statement gets implicitly closed Binary stream returned from a statement becomes invalid if the statement gets implicitly closed Feb 27, 2023
@absci
Copy link
Contributor

absci commented Mar 2, 2023

Hi, we're looking into it.

@absci
Copy link
Contributor

absci commented Mar 15, 2023

Seems the driver is designed to free the stream when the statement closes. But you could pass the $stmt to the function, and unset($stmt) when you're done.

<?php
function get_stream($stmt) {
    sqlsrv_fetch($stmt);
    return sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
}

$conn = sqlsrv_connect('127.0.0.1', [
    'UID' => 'sa',
    'PWD' => '',
]);


$stmt = sqlsrv_query($conn, "SELECT CONVERT(VARBINARY, '0x41')");
$stream = get_stream($stmt);

var_dump(stream_get_meta_data($stream));
unset($stmt);
?>

@morozov
Copy link
Contributor Author

morozov commented Mar 16, 2023

This is still a workaround. The intent is to have a function that accepts a connection and returns the stream. The statement is an implementation detail of the function, not an external dependency.

Seems the driver is designed to free the stream when the statement closes.

This doesn't look like a valid design. If the stream depends on the statement, then the statement should be automatically closed only when it's no longer referenced by the userland code and any internal resources (e.g. streams).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants