Removed the use of a conversion matrix (#1095)

This commit is contained in:
Jenny Tam 2020-02-19 14:27:36 -08:00 committed by GitHub
parent 9534f7b96d
commit af3097d5cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 570 additions and 51 deletions

View file

@ -30,11 +30,6 @@
using namespace core;
// conversion matrix
// each entry holds a function that can perform the conversion or NULL which means the conversion isn't supported
// this is initialized the first time the buffered result set is created.
sqlsrv_buffered_result_set::conv_matrix_t sqlsrv_buffered_result_set::conv_matrix;
namespace {
// *** internal types ***
@ -454,34 +449,6 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm
meta = static_cast<sqlsrv_buffered_result_set::meta_data*>( sqlsrv_malloc( col_count *
sizeof( sqlsrv_buffered_result_set::meta_data )));
// set up the conversion matrix if this is the first time we're called
if( conv_matrix.size() == 0 ) {
conv_matrix[SQL_C_CHAR][SQL_C_CHAR] = &sqlsrv_buffered_result_set::to_same_string;
conv_matrix[SQL_C_CHAR][SQL_C_WCHAR] = &sqlsrv_buffered_result_set::system_to_wide_string;
conv_matrix[SQL_C_CHAR][SQL_C_BINARY] = &sqlsrv_buffered_result_set::to_binary_string;
conv_matrix[SQL_C_CHAR][SQL_C_DOUBLE] = &sqlsrv_buffered_result_set::string_to_double;
conv_matrix[SQL_C_CHAR][SQL_C_LONG] = &sqlsrv_buffered_result_set::string_to_long;
conv_matrix[SQL_C_WCHAR][SQL_C_WCHAR] = &sqlsrv_buffered_result_set::to_same_string;
conv_matrix[SQL_C_WCHAR][SQL_C_BINARY] = &sqlsrv_buffered_result_set::to_binary_string;
conv_matrix[SQL_C_WCHAR][SQL_C_CHAR] = &sqlsrv_buffered_result_set::wide_to_system_string;
conv_matrix[SQL_C_WCHAR][SQL_C_DOUBLE] = &sqlsrv_buffered_result_set::wstring_to_double;
conv_matrix[SQL_C_WCHAR][SQL_C_LONG] = &sqlsrv_buffered_result_set::wstring_to_long;
conv_matrix[SQL_C_BINARY][SQL_C_BINARY] = &sqlsrv_buffered_result_set::to_same_string;
conv_matrix[SQL_C_BINARY][SQL_C_CHAR] = &sqlsrv_buffered_result_set::binary_to_system_string;
conv_matrix[SQL_C_BINARY][SQL_C_WCHAR] = &sqlsrv_buffered_result_set::binary_to_wide_string;
conv_matrix[SQL_C_LONG][SQL_C_DOUBLE] = &sqlsrv_buffered_result_set::long_to_double;
conv_matrix[SQL_C_LONG][SQL_C_LONG] = &sqlsrv_buffered_result_set::to_long;
conv_matrix[SQL_C_LONG][SQL_C_BINARY] = &sqlsrv_buffered_result_set::to_long;
conv_matrix[SQL_C_LONG][SQL_C_CHAR] = &sqlsrv_buffered_result_set::long_to_system_string;
conv_matrix[SQL_C_LONG][SQL_C_WCHAR] = &sqlsrv_buffered_result_set::long_to_wide_string;
conv_matrix[SQL_C_DOUBLE][SQL_C_DOUBLE] = &sqlsrv_buffered_result_set::to_double;
conv_matrix[SQL_C_DOUBLE][SQL_C_BINARY] = &sqlsrv_buffered_result_set::to_double;
conv_matrix[SQL_C_DOUBLE][SQL_C_CHAR] = &sqlsrv_buffered_result_set::double_to_system_string;
conv_matrix[SQL_C_DOUBLE][SQL_C_LONG] = &sqlsrv_buffered_result_set::double_to_long;
conv_matrix[SQL_C_DOUBLE][SQL_C_WCHAR] = &sqlsrv_buffered_result_set::double_to_wide_string;
}
SQLSRV_ENCODING encoding = (( stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) ? stmt->conn->encoding() :
stmt->encoding());
@ -844,18 +811,70 @@ SQLRETURN sqlsrv_buffered_result_set::get_data( _In_ SQLUSMALLINT field_index, _
*out_buffer_length = SQL_NULL_DATA;
return SQL_SUCCESS;
}
// check to make sure the conversion type is valid
conv_matrix_t::const_iterator conv_iter = conv_matrix.find( meta[field_index].c_type );
if( conv_iter == conv_matrix.end() || conv_iter->second.find( target_type ) == conv_iter->second.end() ) {
last_error = new (sqlsrv_malloc( sizeof( sqlsrv_error )))
sqlsrv_error( (SQLCHAR*) "07006", (SQLCHAR*) "Restricted data type attribute violation", 0 );
return SQL_ERROR;
switch (meta[field_index].c_type) {
case SQL_C_CHAR:
switch (target_type) {
case SQL_C_CHAR: return sqlsrv_buffered_result_set::to_same_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_WCHAR: return sqlsrv_buffered_result_set::system_to_wide_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_BINARY: return sqlsrv_buffered_result_set::to_binary_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_DOUBLE: return sqlsrv_buffered_result_set::string_to_double(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_LONG: return sqlsrv_buffered_result_set::string_to_long(field_index, buffer, buffer_length, out_buffer_length);
default:
break;
}
break;
case SQL_C_WCHAR:
switch (target_type) {
case SQL_C_WCHAR: return sqlsrv_buffered_result_set::to_same_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_BINARY: return sqlsrv_buffered_result_set::to_binary_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_CHAR: return sqlsrv_buffered_result_set::wide_to_system_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_DOUBLE: return sqlsrv_buffered_result_set::wstring_to_double(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_LONG: return sqlsrv_buffered_result_set::wstring_to_long(field_index, buffer, buffer_length, out_buffer_length);
default:
break;
}
break;
case SQL_C_BINARY:
switch (target_type) {
case SQL_C_BINARY: return sqlsrv_buffered_result_set::to_same_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_CHAR: return sqlsrv_buffered_result_set::binary_to_system_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_WCHAR: return sqlsrv_buffered_result_set::binary_to_wide_string(field_index, buffer, buffer_length, out_buffer_length);
default:
break;
}
break;
case SQL_C_LONG:
switch (target_type) {
case SQL_C_DOUBLE: return sqlsrv_buffered_result_set::long_to_double(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_LONG: return sqlsrv_buffered_result_set::to_long(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_BINARY: return sqlsrv_buffered_result_set::to_long(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_CHAR: return sqlsrv_buffered_result_set::long_to_system_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_WCHAR: return sqlsrv_buffered_result_set::long_to_wide_string(field_index, buffer, buffer_length, out_buffer_length);
default:
break;
}
break;
case SQL_C_DOUBLE:
switch (target_type) {
case SQL_C_DOUBLE: return sqlsrv_buffered_result_set::to_double(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_BINARY: return sqlsrv_buffered_result_set::to_double(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_CHAR: return sqlsrv_buffered_result_set::double_to_system_string(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_LONG: return sqlsrv_buffered_result_set::double_to_long(field_index, buffer, buffer_length, out_buffer_length);
case SQL_C_WCHAR: return sqlsrv_buffered_result_set::double_to_wide_string(field_index, buffer, buffer_length, out_buffer_length);
default:
break;
}
break;
default:
break;
}
return (( this )->*( conv_matrix[meta[field_index].c_type][target_type] ))( field_index, buffer, buffer_length,
out_buffer_length );
// Should not have reached here, return an error
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error)))
sqlsrv_error((SQLCHAR*) "07006", (SQLCHAR*) "Restricted data type attribute violation", 0);
return SQL_ERROR;
}
SQLRETURN sqlsrv_buffered_result_set::get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,

View file

@ -1746,13 +1746,6 @@ struct sqlsrv_buffered_result_set : public sqlsrv_result_set {
sqlsrv_malloc_auto_ptr<SQLCHAR> temp_string; // temp buffer to hold a converted field while in use
SQLLEN temp_length; // number of bytes in the temp conversion buffer
typedef SQLRETURN (sqlsrv_buffered_result_set::*conv_fn)( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
_Inout_ SQLLEN* out_buffer_length );
typedef std::map< SQLINTEGER, std::map< SQLINTEGER, conv_fn > > conv_matrix_t;
// two dimentional sparse matrix that holds the [from][to] functions that do conversions
static conv_matrix_t conv_matrix;
// string conversion functions
SQLRETURN binary_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
_Inout_ SQLLEN* out_buffer_length );

View file

@ -1799,11 +1799,11 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
case SQLSRV_PHPTYPE_INT:
{
sqlsrv_malloc_auto_ptr<long> field_value_temp;
field_value_temp = static_cast<long*>( sqlsrv_malloc( sizeof( long )));
sqlsrv_malloc_auto_ptr<SQLLEN> field_value_temp;
field_value_temp = static_cast<SQLLEN*>( sqlsrv_malloc( sizeof( SQLLEN )));
*field_value_temp = 0;
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ),
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( SQLLEN ),
field_len, true /*handle_warning*/ TSRMLS_CC );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {

View file

@ -0,0 +1,229 @@
--TEST--
Prepare with cursor buffered and fetch a variety of types converted to different types
--DESCRIPTION--
Test various conversion functionalites for buffered queries with PDO_SQLSRV.
--SKIPIF--
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$tableName = 'pdoFetchingClientBuffer';
$violation = 'Restricted data type attribute violation';
$outOfRange = 'Numeric value out of range';
$truncation = 'Fractional truncation';
$epsilon = 0.00001;
function fetchAsUTF8($conn, $tableName, $inputs)
{
$query = "SELECT * FROM $tableName";
try {
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
// Fetch all fields as UTF-8 strings
for ($i = 0; $i < count($inputs); $i++) {
$stmt->execute();
$f = $stmt->fetchColumn($i);
if ($f !== $inputs[$i]) {
var_dump($f);
}
}
} catch (PdoException $e) {
echo "Caught exception in fetchAsUTF8:\n";
echo $e->getMessage() . PHP_EOL;
}
}
function fetchArray($conn, $tableName, $inputs)
{
$query = "SELECT * FROM $tableName";
try {
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
// By default, even numeric or datetime fields are fetched as strings
$result = $stmt->fetch(PDO::FETCH_NUM);
for ($i = 0; $i < count($inputs); $i++) {
if ($result[$i] !== $inputs[$i]) {
var_dump($f);
}
}
} catch (PdoException $e) {
echo "Caught exception in fetchArray:\n";
echo $e->getMessage() . PHP_EOL;
}
}
function fetchBinaryAsNumber($conn, $tableName, $inputs)
{
global $violation;
$query = "SELECT c1 FROM $tableName";
try {
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED, PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE=>true));
$stmt->execute();
$stmt->bindColumn('c1', $binaryValue, PDO::PARAM_INT);
$row = $stmt->fetch(PDO::FETCH_BOUND);
echo "in fetchBinaryAsNumber: exception should have been thrown!\n";
} catch (PdoException $e) {
// The varbinary field - expect the violation error
if (strpos($e->getMessage(), $violation) === false) {
echo "in fetchBinaryAsNumber: expected '$violation' but caught this:\n";
echo $e->getMessage() . PHP_EOL;
}
}
}
function fetchBinaryAsBinary($conn, $tableName, $inputs)
{
try {
$query = "SELECT c1 FROM $tableName";
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
$stmt->bindColumn('c1', $binaryValue, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
$row = $stmt->fetch(PDO::FETCH_BOUND);
if ($binaryValue !== $inputs[0]) {
echo "Fetched binary value unexpected: $binaryValue\n";
}
} catch (PdoException $e) {
echo "Caught exception in fetchBinaryAsBinary:\n";
echo $e->getMessage() . PHP_EOL;
}
}
function fetchFloatAsInt($conn, $tableName)
{
global $truncation;
try {
$query = "SELECT c3 FROM $tableName";
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
$stmt->bindColumn('c3', $floatValue, PDO::PARAM_INT);
$row = $stmt->fetch(PDO::FETCH_BOUND);
// This should return SQL_SUCCESS_WITH_INFO with the truncation error
$info = $stmt->errorInfo();
if ($info[0] != '01S07' || $info[2] !== $truncation) {
print_r($stmt->errorInfo());
}
} catch (PdoException $e) {
echo "Caught exception in fetchFloatAsInt:\n";
echo $e->getMessage() . PHP_EOL;
}
}
function fetchCharAsInt($conn, $tableName, $column)
{
global $outOfRange;
try {
$query = "SELECT $column FROM $tableName";
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
$stmt->bindColumn($column, $value, PDO::PARAM_INT);
$row = $stmt->fetch(PDO::FETCH_BOUND);
// TODO 11297: fix this part outside Windows later
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
echo "in fetchCharAsInt: exception should have been thrown!\n";
} else {
if ($value != 0) {
var_dump($value);
}
}
} catch (PdoException $e) {
// The (n)varchar field - expect the outOfRange error
if (strpos($e->getMessage(), $outOfRange) === false) {
echo "in fetchCharAsInt ($column): expected '$outOfRange' but caught this:\n";
echo $e->getMessage() . PHP_EOL;
}
}
}
function fetchAsNumerics($conn, $tableName, $inputs)
{
// The following calls expect different errors
fetchFloatAsInt($conn, $tableName);
fetchCharAsInt($conn, $tableName, 'c6');
fetchCharAsInt($conn, $tableName, 'c7');
// The following should work
try {
$query = "SELECT c2, c4 FROM $tableName";
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
$stmt->bindColumn('c2', $intValue, PDO::PARAM_INT);
$stmt->bindColumn('c4', $decValue, PDO::PARAM_INT);
$row = $stmt->fetch(PDO::FETCH_BOUND);
if ($intValue !== intval($inputs[1])) {
var_dump($intValue);
}
if ($decValue !== intval($inputs[3])) {
var_dump($decValue);
}
} catch (PdoException $e) {
echo "Caught exception in fetchAsNumerics:\n";
echo $e->getMessage() . PHP_EOL;
}
}
try {
$conn = connect();
$conn->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
$columns = array('c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7');
$types = array('varbinary(10)', 'int', 'float(53)', 'decimal(16, 6)', 'datetime2', 'varchar(50)', 'nvarchar(50)');
$inputs = array('abcdefghij', '34567', '9876.5432', '123456789.012340', '2020-02-02 20:20:20.2220000', 'This is a test', 'Şơмė śäოрŀề');
// Create table
$colMeta = array(new ColumnMeta($types[0], $columns[0]),
new ColumnMeta($types[1], $columns[1]),
new ColumnMeta($types[2], $columns[2]),
new ColumnMeta($types[3], $columns[3]),
new ColumnMeta($types[4], $columns[4]),
new ColumnMeta($types[5], $columns[5]),
new ColumnMeta($types[6], $columns[6]));
createTable($conn, $tableName, $colMeta);
// Prepare the input values and insert one row
$query = "INSERT INTO $tableName VALUES(?, ?, ?, ?, ?, ?, ?)";
$stmt = $conn->prepare($query);
for ($i = 0; $i < count($columns); $i++) {
if ($i == 0) {
$stmt->bindParam($i+1, $inputs[$i], PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
} else {
$stmt->bindParam($i+1, $inputs[$i]);
}
}
$stmt->execute();
unset($stmt);
// Starting fetching using client buffers
fetchAsUTF8($conn, $tableName, $inputs);
fetchArray($conn, $tableName, $inputs);
fetchBinaryAsNumber($conn, $tableName, $inputs);
fetchBinaryAsBinary($conn, $tableName, $inputs);
fetchAsNumerics($conn, $tableName, $inputs);
// dropTable($conn, $tableName);
echo "Done\n";
unset($conn);
} catch (PdoException $e) {
echo $e->getMessage() . PHP_EOL;
}
?>
--EXPECT--
Done

View file

@ -0,0 +1,278 @@
--TEST--
Prepare with cursor buffered and fetch a variety of types converted to different types
--DESCRIPTION--
Test various conversion functionalites for buffered queries with SQLSRV.
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
$violation = 'Restricted data type attribute violation';
$outOfRange = 'Numeric value out of range';
$truncation = 'Fractional truncation';
$epsilon = 0.00001;
function fetchAsUTF8($conn, $tableName, $inputs)
{
$query = "SELECT * FROM $tableName";
$stmt = sqlsrv_query($conn, $query, array(), array("Scrollable"=>SQLSRV_CURSOR_CLIENT_BUFFERED));
if (!$stmt) {
fatalError("In fetchAsUTF8: failed to run query!");
}
if (sqlsrv_fetch($stmt, SQLSRV_FETCH_NUMERIC) === false) {
fatalError("In fetchAsUTF8: failed to fetch the row from $tableName!");
}
// Fetch all fields as UTF-8 strings
for ($i = 0; $i < count($inputs); $i++) {
$f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_STRING('utf-8'));
if ($i == 0) {
if ($inputs[$i] !== hex2bin($f)) {
var_dump($f);
}
} else {
if ($f !== $inputs[$i]) {
var_dump($f);
}
}
}
}
function fetchArray($conn, $tableName, $inputs)
{
$query = "SELECT * FROM $tableName";
$stmt = sqlsrv_prepare($conn, $query, array(), array('Scrollable'=>SQLSRV_CURSOR_CLIENT_BUFFERED, 'ReturnDatesAsStrings' => true));
if (!$stmt) {
fatalError("In fetchArray: failed to prepare query!");
}
$res = sqlsrv_execute($stmt);
if (!$res) {
fatalError("In fetchArray: failed to execute query!");
}
// Fetch fields as an array
$results = sqlsrv_fetch_array($stmt);
if ($results === false) {
fatalError("In fetchArray: failed to fetch the row from $tableName!");
}
for ($i = 0; $i < count($inputs); $i++) {
if ($i == 1) {
$expected = intval($inputs[$i]);
} elseif ($i == 2) {
$expected = floatval($inputs[$i]);
} else {
$expected = $inputs[$i];
}
if ($results[$i] !== $expected) {
echo "in fetchArray: for column $i expected $expected but got: ";
var_dump($results[$i]);
}
}
}
function fetchAsFloats($conn, $tableName, $inputs)
{
global $violation, $outOfRange, $epsilon;
$query = "SELECT * FROM $tableName";
$stmt = sqlsrv_query($conn, $query, array(), array("Scrollable"=>SQLSRV_CURSOR_CLIENT_BUFFERED, 'ReturnDatesAsStrings' => true));
if (!$stmt) {
fatalError("In fetchAsFloats: failed to run query!");
}
if (sqlsrv_fetch($stmt, SQLSRV_FETCH_NUMERIC) === false) {
fatalError("In fetchAsFloats: failed to fetch the row from $tableName!");
}
// Fetch all fields as floats
for ($i = 0; $i < count($inputs); $i++) {
$f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_FLOAT);
if ($i == 0) {
// The varbinary field - expect the violation error
if (strpos(sqlsrv_errors()[0]['message'], $violation) === false) {
var_dump($f);
fatalError("in fetchAsFloats: expected $violation for column $i\n");
}
} elseif ($i < 5) {
$expected = floatval($inputs[$i]);
$diff = abs(($f - $expected) / $expected);
if ($diff > $epsilon) {
echo "in fetchAsFloats: for column $i expected $expected but got: ";
var_dump($f);
}
} else {
// The char fields will get errors too
// TODO 11297: fix this part outside Windows later
if (isWindows()) {
if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) {
var_dump($f);
fatalError("in fetchAsFloats: expected $outOfRange for column $i\n");
}
} else {
if ($f != 0.0) {
var_dump($f);
}
}
}
}
}
function fetchAsInts($conn, $tableName, $inputs)
{
global $violation, $outOfRange, $truncation;
$query = "SELECT * FROM $tableName";
$stmt = sqlsrv_query($conn, $query, array(), array("Scrollable"=>SQLSRV_CURSOR_CLIENT_BUFFERED, 'ReturnDatesAsStrings' => true));
if (!$stmt) {
fatalError("In fetchAsInts: failed to run query!");
}
if (sqlsrv_fetch($stmt, SQLSRV_FETCH_NUMERIC) === false) {
fatalError("In fetchAsInts: failed to fetch the row from $tableName!");
}
// Fetch all fields as integers
for ($i = 0; $i < count($inputs); $i++) {
$f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_INT);
if ($i == 0) {
// The varbinary field - expect the violation error
if (strpos(sqlsrv_errors()[0]['message'], $violation) === false) {
var_dump($f);
fatalError("in fetchAsInts: expected $violation for column $i\n");
}
} elseif ($i == 2) {
// The float field - expect truncation
if (strpos(sqlsrv_errors()[0]['message'], $truncation) === false) {
var_dump($f);
fatalError("in fetchAsInts: expected $truncation for column $i\n");
}
} elseif ($i >= 5) {
// The char fields will get errors too
// TODO 11297: fix this part outside Windows later
if (isWindows()) {
if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) {
var_dump($f);
fatalError("in fetchAsInts: expected $outOfRange for column $i\n");
}
} else {
if ($f != 0) {
var_dump($f);
}
}
} else {
$expected = floor($inputs[$i]);
if ($f != $expected) {
echo "in fetchAsInts: for column $i expected $expected but got: ";
var_dump($f);
}
}
}
}
function fetchAsBinary($conn, $tableName, $inputs)
{
$query = "SELECT c_varbinary FROM $tableName";
$stmt = sqlsrv_prepare($conn, $query, array(), array('Scrollable'=>SQLSRV_CURSOR_CLIENT_BUFFERED));
if (!$stmt) {
fatalError("In fetchAsBinary: failed to prepare query!");
}
$res = sqlsrv_execute($stmt);
if (!$res) {
fatalError("In fetchAsBinary: failed to execute query!");
}
if (sqlsrv_fetch($stmt, SQLSRV_FETCH_NUMERIC) === false) {
fatalError("In fetchAsInts: failed to fetch the row from $tableName!");
}
// Fetch the varbinary field as is
$f = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM("binary"));
if (gettype($f) !== 'resource') {
var_dump($f);
}
// Do not expect errors
$errs = sqlsrv_errors();
if (!empty($errs)) {
var_dump($errs);
}
// Check its value
while (!feof($f)) {
$str = fread($f, 80);
}
if (trim($str) !== $inputs[0]) {
echo "Fetched binary value unexpected: $str\n";
}
}
require_once('MsCommon.inc');
$conn = AE\connect(array('CharacterSet' => 'UTF-8'));
$tableName = 'srvFetchingClientBuffer';
// Create table
$names = array('c_varbinary', 'c_int', 'c_float', 'c_decimal', 'c_datetime2', 'c_varchar', 'c_nvarchar');
$columns = array(new AE\ColumnMeta('varbinary(10)', $names[0]),
new AE\ColumnMeta('int', $names[1]),
new AE\ColumnMeta('float(53)', $names[2]),
new AE\ColumnMeta('decimal(16, 6)', $names[3]),
new AE\ColumnMeta('datetime2', $names[4]),
new AE\ColumnMeta('varchar(50)', $names[5]),
new AE\ColumnMeta('nvarchar(50)', $names[6]));
$stmt = AE\createTable($conn, $tableName, $columns);
if (!$stmt) {
fatalError("Failed to create $tableName!");
}
// Prepare the input values
$inputs = array('abcdefghij', '34567', '9876.5432', '123456789.012340', '2020-02-02 20:20:20.2220000', 'This is a test', 'Şơмė śäოрŀề');
$params = array(array(bin2hex($inputs[0]), SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_BINARY(10)),
$inputs[1], $inputs[2], $inputs[3], $inputs[4], $inputs[5],
array($inputs[6], SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8')));
// Form the insert query
$colStr = '(';
foreach ($names as $name) {
$colStr .= $name . ", ";
}
$colStr = rtrim($colStr, ", ") . ") ";
$insertSql = "INSERT INTO [$tableName] " . $colStr . 'VALUES (?,?,?,?,?,?,?)';
// Insert one row only
$stmt = sqlsrv_prepare($conn, $insertSql, $params);
if ($stmt) {
$res = sqlsrv_execute($stmt);
if (!$res) {
fatalError("Failed to execute insert statement to $tableName!");
}
} else {
fatalError("Failed to prepare insert statement to $tableName!");
}
// Starting fetching using client buffers
fetchAsUTF8($conn, $tableName, $inputs);
fetchArray($conn, $tableName, $inputs);
fetchAsFloats($conn, $tableName, $inputs);
fetchAsInts($conn, $tableName, $inputs);
fetchAsBinary($conn, $tableName, $inputs);
dropTable($conn, $tableName);
echo "Done\n";
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>
--EXPECT--
Done