Removed the use of a conversion matrix (#1095)
This commit is contained in:
parent
9534f7b96d
commit
af3097d5cf
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
229
test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt
Normal file
229
test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt
Normal 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
|
278
test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt
Normal file
278
test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt
Normal 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
|
Loading…
Reference in a new issue