Made changes to output param handling code to convert doubles to ints if necessary

This commit is contained in:
Jenny Tam 2018-04-25 15:43:56 -07:00
parent 16e0b8961f
commit 218497c642
5 changed files with 37 additions and 28 deletions

View file

@ -406,8 +406,8 @@ pdo_error PDO_ERRORS[] = {
{ IMSSP, (SQLCHAR*) "Stored Procedures do not support text, ntext or image as OUTPUT parameters.", -83, false }
},
{
SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH,
{ IMSSP, (SQLCHAR*) "Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.", -84, false }
SQLSRV_ERROR_DOUBLE_CONVERSION_FAILED,
{ IMSSP, (SQLCHAR*) "Error converting a double value to an integer.", -84, false }
},
{ UINT_MAX, {} }
};

View file

@ -1311,23 +1311,25 @@ struct sqlsrv_output_param {
zval* param_z;
SQLSRV_ENCODING encoding;
SQLUSMALLINT param_num; // used to index into the ind_or_len of the statement
SQLLEN original_buffer_len; // used to make sure the returned length didn't overflow the buffer
SQLUSMALLINT param_num; // used to index into the ind_or_len of the statement
SQLLEN original_buffer_len; // used to make sure the returned length didn't overflow the buffer
SQLSRV_PHPTYPE php_out_type; // used to convert output param if necessary
bool is_bool;
// string output param constructor
sqlsrv_output_param( _In_ zval* p_z, _In_ SQLSRV_ENCODING enc, _In_ int num, _In_ SQLUINTEGER buffer_len ) :
param_z( p_z ), encoding( enc ), param_num( num ), original_buffer_len( buffer_len ), is_bool( false )
param_z(p_z), encoding(enc), param_num(num), original_buffer_len(buffer_len), is_bool(false), php_out_type(SQLSRV_PHPTYPE_INVALID)
{
}
// every other type output parameter constructor
sqlsrv_output_param( _In_ zval* p_z, _In_ int num, _In_ bool is_bool ) :
sqlsrv_output_param( _In_ zval* p_z, _In_ int num, _In_ bool is_bool, _In_ SQLSRV_PHPTYPE php_out_type) :
param_z( p_z ),
encoding( SQLSRV_ENCODING_INVALID ),
param_num( num ),
original_buffer_len( -1 ),
is_bool( is_bool )
is_bool( is_bool ),
php_out_type(php_out_type)
{
}
};
@ -1699,7 +1701,7 @@ enum SQLSRV_ERROR_CODES {
SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED,
SQLSRV_ERROR_INVALID_BUFFER_LIMIT,
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,
SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH,
SQLSRV_ERROR_DOUBLE_CONVERSION_FAILED,
// Driver specific error codes starts from here.
SQLSRV_ERROR_DRIVER_SPECIFIC = 1000,

View file

@ -491,7 +491,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
ind_ptr = buffer_len;
if( direction != SQL_PARAM_INPUT ){
// save the parameter so that 1) the buffer doesn't go away, and 2) we can set it to NULL if returned
sqlsrv_output_param output_param( param_ref, static_cast<int>( param_num ), zval_was_bool );
sqlsrv_output_param output_param( param_ref, static_cast<int>( param_num ), zval_was_bool, php_out_type);
save_output_param_for_later( stmt, output_param TSRMLS_CC );
}
}
@ -503,7 +503,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
ind_ptr = buffer_len;
if( direction != SQL_PARAM_INPUT ){
// save the parameter so that 1) the buffer doesn't go away, and 2) we can set it to NULL if returned
sqlsrv_output_param output_param( param_ref, static_cast<int>( param_num ), false );
sqlsrv_output_param output_param( param_ref, static_cast<int>( param_num ), zval_was_bool, php_out_type);
save_output_param_for_later( stmt, output_param TSRMLS_CC );
}
}
@ -2149,8 +2149,19 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
break;
case IS_DOUBLE:
// for a long or a float, simply check if NULL was returned and set the parameter to a PHP null if so
if( stmt->param_ind_ptrs[ output_param->param_num ] == SQL_NULL_DATA ) {
ZVAL_NULL( value_z );
if (stmt->param_ind_ptrs[output_param->param_num] == SQL_NULL_DATA) {
ZVAL_NULL(value_z);
}
else if (output_param->php_out_type == SQLSRV_PHPTYPE_INT) {
if (Z_DVAL_P(value_z) > INT_MAX) {
CHECK_CUSTOM_ERROR(true, stmt, SQLSRV_ERROR_DOUBLE_CONVERSION_FAILED) {
throw core::CoreException();
}
}
convert_to_long(value_z);
if (output_param->is_bool) {
convert_to_boolean(value_z);
}
}
break;
default:

View file

@ -397,8 +397,8 @@ ss_error SS_ERRORS[] = {
{ IMSSP, (SQLCHAR*) "Stored Procedures do not support text, ntext or image as OUTPUT parameters.", -108, false }
},
{
SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH,
{ IMSSP, (SQLCHAR*) "Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.", -109, false }
SQLSRV_ERROR_DOUBLE_CONVERSION_FAILED,
{ IMSSP, (SQLCHAR*)"Error converting a double value to an integer.", -109, false }
},
// terminate the list of errors/warnings

View file

@ -50,23 +50,15 @@ function compareFloats($actual, $expected)
function compareIntegers($det, $rand, $inputValues, $pdoParamType)
{
///////////////////////////////////////////////////////////////////////
// See GitHub issue 707 - Fix this method when the problem is addressed
//
// Assume $pdoParamType is PDO::PARAM_BOOL or PDO::PARAM_INT
if (is_string($det)) {
return (!compareFloats(floatval($det), $inputValues[0])
&& !compareFloats(floatval($rand), $inputValues[1]));
} else {
// if $pdoParamType is PDO::PARAM_BOOL,
// expect bool(true) or bool(false) depending on the rounded input values
// But with AE enabled (aforementioned GitHub issue), the fetched values
// are floats instead, which should be fixed
// if $pdoParamType is PDO::PARAM_BOOL, expect bool(true) or bool(false)
// depending on the rounded input values
$input0 = floor($inputValues[0]); // the positive float
$input1 = ceil($inputValues[1]); // the negative float
if (isAEConnected()) {
$det = boolval(floor($det));
$rand = boolval(ceil($rand));
}
return ($det == boolval($input0) && $rand == boolval($input1));
}
@ -190,10 +182,14 @@ function testOutputDecimals($inout)
if ($found === false) {
printValues($errMsg, $det, $rand, $inputValues);
}
} elseif (!isAEConnected() && $precision >= 16) {
// When not AE enabled, large numbers are expected to
// fail when converting to booleans / integers
$error = "Error converting data type $dataType to int";
} elseif ($precision >= 16) {
// Large numbers are expected to fail when
// converting to booleans / integers
if (isAEConnected()) {
$error = "Error converting a double value to an integer";
} else {
$error = "Error converting data type $dataType to int";
}
$found = strpos($message, $error);
if ($found === false) {
printValues($errMsg, $det, $rand, $inputValues);