-
Notifications
You must be signed in to change notification settings - Fork 373
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
BIGINT as an output param no longer results in value out of range exception when the returned value is larger than a maximum integer #567
Conversation
…_bigint_outparam.phpt
source/shared/core_stmt.cpp
Outdated
match = Z_TYPE_P( param_z ) == IS_LONG; | ||
if( zval_was_long ){ | ||
convert_to_string( param_z ); | ||
encoding = SQLSRV_ENCODING_SYSTEM; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will fix indentation
source/shared/core_stmt.cpp
Outdated
@@ -551,7 +565,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ | |||
buffer, buffer_len TSRMLS_CC ); | |||
|
|||
// save the parameter to be adjusted and/or converted after the results are processed | |||
sqlsrv_output_param output_param( param_ref, encoding, param_num, static_cast<SQLUINTEGER>( buffer_len )); | |||
sqlsrv_output_param output_param( param_ref, encoding, param_num, static_cast<SQLUINTEGER>( buffer_len ), zval_was_long ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will fix indentation
source/shared/core_stmt.cpp
Outdated
if( zval_was_long ){ | ||
convert_to_string( param_z ); | ||
encoding = SQLSRV_ENCODING_SYSTEM; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do any encoding issues relating to use of commas as separators crop up? I should think that convert_to_string just takes the int and converts to a string of digits, eg. 1,000,000 becomes '1000000'. But if not, do we run into any issues handling commas when calling convert_to_double or convert_to_long below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried testing with both encodings (utf-8 and char) and they both are fine. From wheat I researched, user can only retrieve a comma separated integer by explicitly casting an int to a string. If that is the case, the php_out_type would not be INT anymore, instead it would be a string, and the problem with bigint to int conversion would not exist.
As for the second question "do we run into any issues handling commas when calling convert_to_double or convert_to_long below", this will not be a problem since the string retrieved will not have any comma separators.
$tbname = "bigint_table"; | ||
createTable($conn, $tbname, array("c1_bigint" => "bigint")); | ||
|
||
// Create a Store Procedure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*stored
(here and elsewhere)
$conn->exec("TRUNCATE TABLE $tbname"); | ||
|
||
// Insert a small bigint | ||
insertRow($conn, $tbname, array("c1_bigint" => 922337203)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any particular reason for choosing this value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is just a random value truncated from the bigint input
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps add that to comment?
When user initialize an integer in php:
$output = 0;
php interpret this variable as azend_long
.zend_long
has a member of c typelong
to contain the value. A clong
is 4 bytes and the max and min size are 2,147,483,647 and -2,147,483,647 respectively.If the user use
$output
to bind parameter:Everything will be fine if the output of calling the stored procedure is < 2,147,483,647 and > -2,147,483,647. If otherwise however, a value out of range exception is thrown.
The source of misbehavior comes from 2 places:
zend_long
, the sqltype is set tosql_int
. Therefore is the output is greater than max int, the value out of range exception is thrown from SQL Server.sql_bigint
and SQL Server no longer throws an exception, the output variablezend_long
is still not big enough to fit the bigint.To tackle these two problems, when
$output
is first passed to bind parameter, convert it to azend_string
. Then the zend type iszend_string
, the sqltype set by the SQLSRV and PDO_SQLSRV drivers are SQL_* character strings types depending on the encoding. Passing a character strings type to MSODBC has no problem since almost every datatypes can be converted to a character string.When the output it retrieved, the drivers now compare to see if the retrieved value is less than max int. If it is, convert it back to
zend_long
(the reason to convert back is so it doesn't affect the existing users). If it is larger than max int, leave it as azend_string
, sincezend_long
will not hold the value properly.This change is