Merge pull request #292 from v-dareck/bindparam_out_string_fault

Add check for SQL_NO_TOTAL for SQLBindParameter out parameter
This commit is contained in:
Jenny Tam 2017-02-20 07:49:17 -08:00 committed by GitHub
commit cc925ad9b3
2 changed files with 468 additions and 0 deletions

View file

@ -2030,6 +2030,15 @@ void finalize_output_parameters( sqlsrv_stmt* stmt TSRMLS_DC )
throw core::CoreException();
}
// For ODBC 11+ see https://msdn.microsoft.com/en-us/library/jj219209.aspx
// A length value of SQL_NO_TOTAL for SQLBindParameter indicates that the buffer contains up to
// output_param->original_buffer_len data and is NULL terminated.
// The IF statement can be true when using connection pooling with unixODBC 2.3.4.
if ( str_len == SQL_NO_TOTAL )
{
str_len = output_param->original_buffer_len - null_size;
}
// if it's not in the 8 bit encodings, then it's in UTF-16
if( output_param->encoding != SQLSRV_ENCODING_CHAR && output_param->encoding != SQLSRV_ENCODING_BINARY ) {
bool converted = convert_zval_string_from_utf16(output_param->encoding, value_z, str_len);

View file

@ -0,0 +1,459 @@
--TEST--
Verify the Binary and Char encoding output when binding output string with SQLSTYPE option with different size.
--DESCRIPTION--
Tests different sizes of output string which may cause ODBC to return trunc error info.
With unixODBC 2.3.4, when connection pooling is enabled, error information maybe returned differently
than older versions (or with pooling disabled).
The NVARCHAR(1) section would cause an ODBC call to return an errorinfo to the driver causing the statement to fail.
With unixODBC 2.3.4 + pooling the statement executes without error.
--FILE--
<?php
require_once("autonomous_setup.php");
$connectionInfo = array("UID"=>"$username", "PWD"=>"$password");
$conn = sqlsrv_connect($serverName, $connectionInfo);
if( $conn === false ) {
die( print_r( sqlsrv_errors(), true ));
}
$conn = null;
$conn = sqlsrv_connect($serverName, $connectionInfo);
if( $conn === false ) {
die( print_r( sqlsrv_errors(), true ));
}
$bindtable = "#BindStringTest";
$sproc = "#uspPerson";
// Create table
$stmt = sqlsrv_query( $conn, "CREATE TABLE $bindtable (PersonID int, Name nvarchar(50))" );
if( $stmt === false ) {
die( print_r( sqlsrv_errors(), true ));
}
$stmt = sqlsrv_query( $conn, "INSERT INTO $bindtable (PersonID, Name) VALUES (10, N'Miller')" );
if( $stmt === false ) {
die( print_r( sqlsrv_errors(), true ));
}
$stmt = sqlsrv_query( $conn, "INSERT INTO $bindtable (PersonID, Name) VALUES (11, N'JSmith')" );
if( $stmt === false ) {
die( print_r( sqlsrv_errors(), true ));
}
$tsql_createSP = "CREATE PROCEDURE $sproc
@id int, @return nvarchar(50) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET @return = (SELECT Name FROM $bindtable WHERE PersonID = @id)
END";
$stmt = sqlsrv_query( $conn, $tsql_createSP);
if( $stmt === false )
{
echo "Error in executing statement 2.\n";
die( print_r( sqlsrv_errors(), true));
}
$tsql_callSP = "{call $sproc( ? , ?)}";
//***********************************************************************************************
echo "NVARCHAR(32)\n";
echo "---------Encoding char-----------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),
SQLSRV_SQLTYPE_NVARCHAR(32)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) === false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 6;
$expectedValue = "Miller";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
echo "---------Encoding binary---------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_NVARCHAR(32)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) == false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 12;
$expectedValue = "M\0i\0l\0l\0e\0r\0";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
//***********************************************************************************************
echo "\n\n";
echo "NVARCHAR(50)\n";
echo "---------Encoding char-----------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),
SQLSRV_SQLTYPE_NVARCHAR(50)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) === false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 6;
$expectedValue = "Miller";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
echo "---------Encoding binary---------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_NVARCHAR(50)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) == false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 12;
$expectedValue = "M\0i\0l\0l\0e\0r\0";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
//***********************************************************************************************
echo "\n\n";
echo "NVARCHAR(1)\n";
echo "---------Encoding char-----------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),
SQLSRV_SQLTYPE_NVARCHAR(1)
));
// with unixODBC 2.3.4 connection pooling the statement may not fail.
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) === false)
{
echo "Statement should fail\n";
}
$expectedLength = 1;
$expectedValue = "M";
$actualValue = $return;
$actualLength = strlen($return);
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
echo "---------Encoding binary---------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_NVARCHAR(1)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) == false)
{
echo "Statement should fail\n";
}
$expectedLength = 2;
$expectedValue = "M\0";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
//***********************************************************************************************
echo "\n\n";
echo "NCHAR(32)\n";
echo "---------Encoding char-----------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),
SQLSRV_SQLTYPE_NCHAR(32)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) === false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 32;
$expectedValue = "Miller ";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
echo "---------Encoding binary---------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_NCHAR(32)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) == false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 64;
$expectedValue = "M\0i\0l\0l\0e\0r\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
//***********************************************************************************************
echo "\n\n";
echo "NCHAR(0)\n";
echo "---------Encoding char-----------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),
SQLSRV_SQLTYPE_NCHAR(0)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) === false)
{
echo "Statement should fail\n";
}
$expectedLength = 0;
$expectedValue = "";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
echo "---------Encoding binary---------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_NCHAR(0)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) == false)
{
echo "Statement should fail\n";
}
$expectedLength = 0;
$expectedValue = "";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
//***********************************************************************************************
echo "\n\n";
echo "NCHAR(50)\n";
echo "---------Encoding char-----------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),
SQLSRV_SQLTYPE_NCHAR(50)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) === false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 50;
$expectedValue = "Miller ";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
echo "---------Encoding binary---------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_NCHAR(50)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) == false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 100;
$expectedValue = "M\0i\0l\0l\0e\0r\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0";
$actualLength = strlen($return);
$actualValue = $return;
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
//***********************************************************************************************
// NCHAR 1: less than length of the returned value
echo "\n\n";
echo "NCHAR(1)\n";
echo "---------Encoding char-----------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),
SQLSRV_SQLTYPE_NCHAR(1)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) === false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 1;
$expectedValue = "M";
$actualValue = $return;
$actualLength = strlen($return);
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
echo "---------Encoding binary---------\n";
$id = 10;
$return = "";
$params = array(
array($id, SQLSRV_PARAM_IN),
array(&$return, SQLSRV_PARAM_OUT,
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
SQLSRV_SQLTYPE_NCHAR(1)
));
if( $stmt = sqlsrv_query($conn, $tsql_callSP, $params) == false)
{
print_r( sqlsrv_errors(), true);
}
$expectedLength = 2;
$expectedValue = "M\0";
$actualValue = $return;
$actualLength = strlen($return);
compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue );
sqlsrv_close($conn);
$status = true;
/**
* Compares actual output to expected one
* @param $expectedLength The length of the expected value
* @param $expectedValue The expected value
* @param $actualLength The length of the actual value
* @param $actualValue The actual value
*/
function compareResults ( $expectedLength, $expectedValue, $actualLength, $actualValue )
{
$match = false;
if ( $expectedLength == $actualLength)
{
if ( strncmp ( $actualValue, $expectedValue, $expectedLength ) == 0 )
{
$match = true;
}
}
if ( !$match )
{
echo "The actual result is different from the expected one \n";
}
else
{
echo "The actual result is the same as the expected one \n";
}
}
?>
--EXPECT--
NVARCHAR(32)
---------Encoding char-----------
The actual result is the same as the expected one
---------Encoding binary---------
The actual result is the same as the expected one
NVARCHAR(50)
---------Encoding char-----------
The actual result is the same as the expected one
---------Encoding binary---------
The actual result is the same as the expected one
NVARCHAR(1)
---------Encoding char-----------
Statement should fail
The actual result is the same as the expected one
---------Encoding binary---------
Statement should fail
The actual result is the same as the expected one
NCHAR(32)
---------Encoding char-----------
The actual result is the same as the expected one
---------Encoding binary---------
The actual result is the same as the expected one
NCHAR(0)
---------Encoding char-----------
Statement should fail
The actual result is the same as the expected one
---------Encoding binary---------
Statement should fail
The actual result is the same as the expected one
NCHAR(50)
---------Encoding char-----------
The actual result is the same as the expected one
---------Encoding binary---------
The actual result is the same as the expected one
NCHAR(1)
---------Encoding char-----------
The actual result is the same as the expected one
---------Encoding binary---------
The actual result is the same as the expected one