convert long output param to string, then convert back to long if less than max int

This commit is contained in:
v-kaywon 2017-10-11 18:03:14 -07:00
parent edac5b2d25
commit a0e886273f
6 changed files with 351 additions and 6 deletions

View file

@ -1322,10 +1322,11 @@ struct sqlsrv_output_param {
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
bool is_bool;
bool is_long;
// 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 )
sqlsrv_output_param( _In_ zval* p_z, _In_ SQLSRV_ENCODING enc, _In_ int num, _In_ SQLUINTEGER buffer_len, _In_ bool is_long ) :
param_z( p_z ), encoding( enc ), param_num( num ), original_buffer_len( buffer_len ), is_bool( false ), is_long( is_long )
{
}
@ -1335,7 +1336,8 @@ struct sqlsrv_output_param {
encoding( SQLSRV_ENCODING_INVALID ),
param_num( num ),
original_buffer_len( -1 ),
is_bool( is_bool )
is_bool( is_bool ),
is_long( false )
{
}
};

View file

@ -373,6 +373,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
}
bool zval_was_null = ( Z_TYPE_P( param_z ) == IS_NULL );
bool zval_was_bool = ( Z_TYPE_P( param_z ) == IS_TRUE || Z_TYPE_P( param_z ) == IS_FALSE );
bool zval_was_long = ( Z_TYPE_P( param_z ) == IS_LONG && php_out_type == SQLSRV_PHPTYPE_INT );
// if the user asks for for a specific type for input and output, make sure the data type we send matches the data we
// type we expect back, since we can only send and receive the same type. Anything can be converted to a string, so
// we always let that match if they want a string back.
@ -383,7 +384,13 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
if( zval_was_null || zval_was_bool ) {
convert_to_long( param_z );
}
match = Z_TYPE_P( param_z ) == IS_LONG;
if( zval_was_long ){
convert_to_string( param_z );
match = Z_TYPE_P( param_z ) == IS_STRING;
}
else {
match = Z_TYPE_P(param_z) == IS_LONG;
}
break;
case SQLSRV_PHPTYPE_FLOAT:
if( zval_was_null ) {
@ -415,7 +422,12 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
if( direction == SQL_PARAM_OUTPUT ) {
switch( php_out_type ) {
case SQLSRV_PHPTYPE_INT:
convert_to_long( param_z );
if( zval_was_long ){
convert_to_string( param_z );
}
else {
convert_to_long( param_z );
}
break;
case SQLSRV_PHPTYPE_FLOAT:
convert_to_double( param_z );
@ -551,7 +563,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 );
save_output_param_for_later( stmt, output_param TSRMLS_CC );
@ -2127,6 +2139,15 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
else {
core::sqlsrv_zval_stringl(value_z, str, str_len);
}
if ( output_param->is_long ) {
zval* value_z_temp = ( zval * )sqlsrv_malloc( sizeof( zval ));
ZVAL_COPY( value_z_temp, value_z );
convert_to_double( value_z_temp );
if ( Z_DVAL_P( value_z_temp ) > INT_MIN && Z_DVAL_P( value_z_temp ) < INT_MAX ) {
convert_to_long( value_z );
}
sqlsrv_free( value_z_temp );
}
}
break;
case IS_LONG:

View file

@ -0,0 +1,82 @@
--TEST--
Test for binding bigint output and inout parameters
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$conn = connect();
// Create the table
$tbname = "bigint_table";
createTable($conn, $tbname, array("c1_bigint" => "bigint"));
// Create a Store Procedure
$spname = "selectBigint";
$spSql = "CREATE PROCEDURE $spname (@c1_bigint bigint OUTPUT) AS
SELECT @c1_bigint = c1_bigint FROM $tbname";
$conn->query($spSql);
// Insert a large bigint
insertRow($conn, $tbname, array("c1_bigint" => 922337203685479936));
// Call store procedure with output
$outSql = "{CALL $spname (?)}";
$bigintOut = 0;
$stmt = $conn->prepare($outSql);
$stmt->bindParam(1, $bigintOut, PDO::PARAM_INT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
printf("Large bigint output:\n" );
var_dump($bigintOut);
printf("\n");
// Call store procedure with inout
$bigintOut = 0;
$stmt = $conn->prepare($outSql);
$stmt->bindParam(1, $bigintOut, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
printf("Large bigint inout:\n" );
var_dump($bigintOut);
printf("\n");
$conn->exec("TRUNCATE TABLE $tbname");
// Insert a small bigint
insertRow($conn, $tbname, array("c1_bigint" => 922337203));
// Call store procedure with output
$bigintOut = 0;
$stmt = $conn->prepare($outSql);
$stmt->bindParam(1, $bigintOut, PDO::PARAM_INT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
printf("Small bigint output:\n" );
var_dump($bigintOut);
printf("\n");
// Call store procedure with inout
$bigintOut = 0;
$stmt = $conn->prepare($outSql);
$stmt->bindParam(1, $bigintOut, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
printf("Small bigint inout:\n" );
var_dump($bigintOut);
printf("\n");
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($stmt);
unset($conn);
?>
--EXPECT--
Large bigint output:
string(18) "922337203685479936"
Large bigint inout:
string(18) "922337203685479936"
Small bigint output:
int(922337203)
Small bigint inout:
int(922337203)

View file

@ -0,0 +1,82 @@
--TEST--
Test for binding boolean output and inout parameters
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$conn = connect();
// Create the table
$tbname = "bool_table";
createTable($conn, $tbname, array("c1_bool" => "int"));
// Create a Store Procedure
$spname = "selectBool";
$spSql = "CREATE PROCEDURE $spname (@c1_bool int OUTPUT) AS
SELECT @c1_bool = c1_bool FROM $tbname";
$conn->query($spSql);
// Insert 1
insertRow($conn, $tbname, array("c1_bool" => 1));
// Call store procedure with output
$outSql = "{CALL $spname (?)}";
$boolOut = false;
$stmt = $conn->prepare($outSql);
$stmt->bindParam(1, $boolOut, PDO::PARAM_INT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
printf("True bool output:\n" );
var_dump($boolOut);
printf("\n");
// Call store procedure with inout
$boolOut = false;
$stmt = $conn->prepare($outSql);
$stmt->bindParam(1, $boolOut, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
printf("True bool inout:\n" );
var_dump($boolOut);
printf("\n");
$conn->exec("TRUNCATE TABLE $tbname");
// Insert 0
insertRow($conn, $tbname, array("c1_bool" => 0));
// Call store procedure with output
$boolOut = true;
$stmt = $conn->prepare($outSql);
$stmt->bindParam(1, $boolOut, PDO::PARAM_INT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
printf("True bool output:\n" );
var_dump($boolOut);
printf("\n");
// Call store procedure with inout
$boolOut = true;
$stmt = $conn->prepare($outSql);
$stmt->bindParam(1, $boolOut, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->execute();
printf("True bool inout:\n" );
var_dump($boolOut);
printf("\n");
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($stmt);
unset($conn);
?>
--EXPECT--
True bool output:
int(1)
True bool inout:
int(1)
True bool output:
int(0)
True bool inout:
int(0)

View file

@ -0,0 +1,79 @@
--TEST--
Test for binding bigint output and inout parameters
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once("MsHelper.inc");
$conn = AE\connect();
// Create the table
$tbname = "bigint_table";
AE\createTable($conn, $tbname, array(new AE\ColumnMeta("bigint", "c1_bigint")));
// Create a Store Procedure with output
$spname = "selectBigint";
$spSql = "CREATE PROCEDURE $spname (@c1_bigint bigint OUTPUT) AS
SELECT @c1_bigint = c1_bigint FROM $tbname";
sqlsrv_query( $conn, $spSql );
// Insert a large bigint
AE\insertRow($conn, $tbname, array("c1_bigint" => 922337203685479936));
// Call store procedure with SQLSRV_PARAM_OUT
$outSql = "{CALL $spname (?)}";
$bigintOut = 0;
$stmt = sqlsrv_prepare($conn, $outSql, array(array(&$bigintOut, SQLSRV_PARAM_OUT)));
sqlsrv_execute($stmt);
printf("Large bigint output:\n");
var_dump($bigintOut);
printf("\n");
// Call store procedure with SQLSRV_PARAM_INOUT
$bigintOut = 0;
$stmt = sqlsrv_prepare($conn, $outSql, array(array(&$bigintOut, SQLSRV_PARAM_INOUT)));
sqlsrv_execute($stmt);
printf("Large bigint inout:\n");
var_dump($bigintOut);
printf("\n");
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
// Insert a small bigint
AE\insertRow($conn, $tbname, array("c1_bigint" => 922337203));
// Call store procedure with SQLSRV_PARAM_OUT
$bigintOut = 0;
$stmt = sqlsrv_prepare($conn, $outSql, array(array(&$bigintOut, SQLSRV_PARAM_OUT)));
sqlsrv_execute($stmt);
printf("Small bigint output:\n");
var_dump($bigintOut);
printf("\n");
// Call store procedure with SQLSRV_PARAM_INOUT
$bigintOut = 0;
$stmt = sqlsrv_prepare($conn, $outSql, array(array(&$bigintOut, SQLSRV_PARAM_INOUT)));
sqlsrv_execute($stmt);
printf("Small bigint inout:\n");
var_dump($bigintOut);
printf("\n");
dropProc($conn, $spname);
dropTable($conn, $tbname);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>
--EXPECT--
Large bigint output:
string(18) "922337203685479936"
Large bigint inout:
string(18) "922337203685479936"
Small bigint output:
int(922337203)
Small bigint inout:
int(922337203)

View file

@ -0,0 +1,79 @@
--TEST--
Test for binding boolean output and inout parameters
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once("MsHelper.inc");
$conn = AE\connect();
// Create the table
$tbname = "bool_table";
AE\createTable($conn, $tbname, array(new AE\ColumnMeta("int", "c1_bool")));
// Create a Store Procedure with output
$spname = "selectBool";
$spSql = "CREATE PROCEDURE $spname (@c1_bool int OUTPUT) AS
SELECT @c1_bool = c1_bool FROM $tbname";
sqlsrv_query( $conn, $spSql );
// Insert 1
AE\insertRow($conn, $tbname, array("c1_bool" => 1));
// Call store procedure with SQLSRV_PARAM_OUT
$outSql = "{CALL $spname (?)}";
$boolOut = false;
$stmt = sqlsrv_prepare($conn, $outSql, array(array(&$boolOut, SQLSRV_PARAM_OUT, SQLSRV_PHPTYPE_INT)));
sqlsrv_execute($stmt);
printf("True bool output:\n");
var_dump($boolOut);
printf("\n");
// Call store procedure with SQLSRV_PARAM_INOUT
$boolOut = false;
$stmt = sqlsrv_prepare($conn, $outSql, array(array(&$boolOut, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_INT)));
sqlsrv_execute($stmt);
printf("True bool inout:\n");
var_dump($boolOut);
printf("\n");
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
// Insert 0
AE\insertRow($conn, $tbname, array("c1_bool" => 0));
// Call store procedure with SQLSRV_PARAM_OUT
$boolOut = true;
$stmt = sqlsrv_prepare($conn, $outSql, array(array(&$boolOut, SQLSRV_PARAM_OUT, SQLSRV_PHPTYPE_INT)));
sqlsrv_execute($stmt);
printf("False bool output:\n");
var_dump($boolOut);
printf("\n");
// Call store procedure with SQLSRV_PARAM_INOUT
$boolOut = true;
$stmt = sqlsrv_prepare($conn, $outSql, array(array(&$boolOut, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_INT)));
sqlsrv_execute($stmt);
printf("False bool inout:\n");
var_dump($boolOut);
printf("\n");
dropProc($conn, $spname);
dropTable($conn, $tbname);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>
--EXPECT--
True bool output:
bool(true)
True bool inout:
bool(true)
False bool output:
bool(false)
False bool inout:
bool(false)