Skip to content

Commit

Permalink
convert long output param to string, then convert back to long if les…
Browse files Browse the repository at this point in the history
…s than max int
  • Loading branch information
yukiwongky committed Oct 12, 2017
1 parent edac5b2 commit a0e8862
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 6 deletions.
8 changes: 5 additions & 3 deletions source/shared/core_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
{
}

Expand All @@ -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 )
{
}
};
Expand Down
27 changes: 24 additions & 3 deletions source/shared/core_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 ) {
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );

Expand Down Expand Up @@ -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:
Expand Down
82 changes: 82 additions & 0 deletions test/functional/pdo_sqlsrv/pdo_bigint_outparam.phpt
Original file line number Diff line number Diff line change
@@ -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)
82 changes: 82 additions & 0 deletions test/functional/pdo_sqlsrv/pdo_bool_outparam.phpt
Original file line number Diff line number Diff line change
@@ -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)
79 changes: 79 additions & 0 deletions test/functional/sqlsrv/sqlsrv_bigint_outparam.phpt
Original file line number Diff line number Diff line change
@@ -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)
Loading

0 comments on commit a0e8862

Please sign in to comment.