Simplied conversions from strings to numbers (#1146)
This commit is contained in:
parent
d5e1d8cfbc
commit
ecbd53f712
|
@ -262,64 +262,6 @@ std::string getUTF8StringFromString( _In_z_ const char* source )
|
||||||
|
|
||||||
#endif // !_WIN32
|
#endif // !_WIN32
|
||||||
|
|
||||||
template <typename Number, typename Char>
|
|
||||||
SQLRETURN string_to_number( _In_z_ Char* string_data, SQLLEN str_len, _Out_writes_bytes_(*out_buffer_length) void* buffer, SQLLEN buffer_length,
|
|
||||||
_Inout_ SQLLEN* out_buffer_length, _Inout_ sqlsrv_error_auto_ptr& last_error )
|
|
||||||
{
|
|
||||||
Number* number_data = reinterpret_cast<Number*>( buffer );
|
|
||||||
#ifdef _WIN32
|
|
||||||
std::locale loc; // default locale should match system
|
|
||||||
std::basic_istringstream<Char> is;
|
|
||||||
is.str( string_data );
|
|
||||||
is.imbue( loc );
|
|
||||||
std::ios_base::iostate st = 0;
|
|
||||||
|
|
||||||
std::use_facet< std::num_get< Char > >( loc ).get( std::basic_istream<Char>::_Iter( is.rdbuf()), std::basic_istream<Char>::_Iter( 0 ), is, st, *number_data );
|
|
||||||
|
|
||||||
if ( st & std::ios_base::failbit ) {
|
|
||||||
last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error(( SQLCHAR* ) "22003", ( SQLCHAR* ) "Numeric value out of range", 103 );
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_buffer_length = sizeof( Number );
|
|
||||||
#else
|
|
||||||
std::string str = getUTF8StringFromString( string_data );
|
|
||||||
|
|
||||||
std::istringstream is( str );
|
|
||||||
std::locale loc; // default locale should match system
|
|
||||||
is.imbue( loc );
|
|
||||||
|
|
||||||
auto& facet = std::use_facet<std::num_get<char>>( is.getloc() );
|
|
||||||
std::istreambuf_iterator<char> beg( is ), end;
|
|
||||||
std::ios_base::iostate err = std::ios_base::goodbit;
|
|
||||||
|
|
||||||
if ( std::is_integral<Number>::value )
|
|
||||||
{
|
|
||||||
long number;
|
|
||||||
facet.get( beg, end, is, err, number );
|
|
||||||
|
|
||||||
*number_data = number;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double number;
|
|
||||||
facet.get( beg, end, is, err, number );
|
|
||||||
|
|
||||||
*number_data = number;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_buffer_length = sizeof( Number );
|
|
||||||
|
|
||||||
if ( is.fail() )
|
|
||||||
{
|
|
||||||
last_error = new ( sqlsrv_malloc(sizeof( sqlsrv_error ))) sqlsrv_error(( SQLCHAR* ) "22003", ( SQLCHAR* ) "Numeric value out of range", 103 );
|
|
||||||
return SQL_ERROR;
|
|
||||||
}
|
|
||||||
#endif // _WIN32
|
|
||||||
return SQL_SUCCESS;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// "closure" for the hash table destructor
|
// "closure" for the hash table destructor
|
||||||
struct row_dtor_closure {
|
struct row_dtor_closure {
|
||||||
|
|
||||||
|
@ -851,7 +793,6 @@ SQLRETURN sqlsrv_buffered_result_set::get_data( _In_ SQLUSMALLINT field_index, _
|
||||||
case SQL_C_LONG: return sqlsrv_buffered_result_set::to_long(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_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_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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -862,7 +803,6 @@ SQLRETURN sqlsrv_buffered_result_set::get_data( _In_ SQLUSMALLINT field_index, _
|
||||||
case SQL_C_BINARY: 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_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_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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1082,23 +1022,6 @@ SQLRETURN sqlsrv_buffered_result_set::double_to_system_string( _In_ SQLSMALLINT
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLRETURN sqlsrv_buffered_result_set::double_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_bytes_to_opt_(buffer_length, *out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
|
||||||
_Inout_ SQLLEN* out_buffer_length )
|
|
||||||
{
|
|
||||||
SQLSRV_ASSERT( meta[field_index].c_type == SQL_C_DOUBLE, "Invalid conversion to wide string" );
|
|
||||||
SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::double_to_wide_string" );
|
|
||||||
|
|
||||||
unsigned char* row = get_row();
|
|
||||||
double* double_data = reinterpret_cast<double*>( &row[meta[field_index].offset] );
|
|
||||||
SQLRETURN r = SQL_SUCCESS;
|
|
||||||
#ifdef _WIN32
|
|
||||||
r = number_to_string<WCHAR>( double_data, buffer, buffer_length, out_buffer_length, last_error );
|
|
||||||
#else
|
|
||||||
r = number_to_string<char16_t, double>( double_data, buffer, buffer_length, out_buffer_length, last_error );
|
|
||||||
#endif // _WIN32
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
SQLRETURN sqlsrv_buffered_result_set::long_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
SQLRETURN sqlsrv_buffered_result_set::long_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
||||||
_Out_ SQLLEN* out_buffer_length )
|
_Out_ SQLLEN* out_buffer_length )
|
||||||
{
|
{
|
||||||
|
@ -1131,23 +1054,6 @@ SQLRETURN sqlsrv_buffered_result_set::long_to_system_string( _In_ SQLSMALLINT fi
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLRETURN sqlsrv_buffered_result_set::long_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_bytes_to_opt_(buffer_length, *out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
|
||||||
_Inout_ SQLLEN* out_buffer_length )
|
|
||||||
{
|
|
||||||
SQLSRV_ASSERT( meta[field_index].c_type == SQL_C_LONG, "Invalid conversion to wide string" );
|
|
||||||
SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::long_to_wide_string" );
|
|
||||||
|
|
||||||
unsigned char* row = get_row();
|
|
||||||
LONG* long_data = reinterpret_cast<LONG*>( &row[meta[field_index].offset] );
|
|
||||||
SQLRETURN r = SQL_SUCCESS;
|
|
||||||
#ifdef _WIN32
|
|
||||||
r = number_to_string<WCHAR>( long_data, buffer, buffer_length, out_buffer_length, last_error );
|
|
||||||
#else
|
|
||||||
r = number_to_string<char16_t, LONG>( long_data, buffer, buffer_length, out_buffer_length, last_error );
|
|
||||||
#endif // _WIN32
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
SQLRETURN sqlsrv_buffered_result_set::string_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
SQLRETURN sqlsrv_buffered_result_set::string_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
||||||
_Inout_ SQLLEN* out_buffer_length )
|
_Inout_ SQLLEN* out_buffer_length )
|
||||||
{
|
{
|
||||||
|
@ -1157,7 +1063,16 @@ SQLRETURN sqlsrv_buffered_result_set::string_to_double( _In_ SQLSMALLINT field_i
|
||||||
unsigned char* row = get_row();
|
unsigned char* row = get_row();
|
||||||
char* string_data = reinterpret_cast<char*>( &row[meta[field_index].offset] ) + sizeof( SQLULEN );
|
char* string_data = reinterpret_cast<char*>( &row[meta[field_index].offset] ) + sizeof( SQLULEN );
|
||||||
|
|
||||||
return string_to_number<double>( string_data, meta[field_index].length, buffer, buffer_length, out_buffer_length, last_error );
|
double* number_data = reinterpret_cast<double*>(buffer);
|
||||||
|
try {
|
||||||
|
*number_data = std::stod(std::string(string_data));
|
||||||
|
} catch (const std::logic_error& err) {
|
||||||
|
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103);
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_buffer_length = sizeof(double);
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLRETURN sqlsrv_buffered_result_set::wstring_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
SQLRETURN sqlsrv_buffered_result_set::wstring_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
||||||
|
@ -1169,7 +1084,20 @@ SQLRETURN sqlsrv_buffered_result_set::wstring_to_double( _In_ SQLSMALLINT field_
|
||||||
unsigned char* row = get_row();
|
unsigned char* row = get_row();
|
||||||
SQLWCHAR* string_data = reinterpret_cast<SQLWCHAR*>( &row[meta[field_index].offset] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR );
|
SQLWCHAR* string_data = reinterpret_cast<SQLWCHAR*>( &row[meta[field_index].offset] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR );
|
||||||
|
|
||||||
return string_to_number<double>( string_data, meta[field_index].length, buffer, buffer_length, out_buffer_length, last_error );
|
double* number_data = reinterpret_cast<double*>(buffer);
|
||||||
|
try {
|
||||||
|
#ifdef _WIN32
|
||||||
|
*number_data = std::stod(std::wstring(string_data));
|
||||||
|
#else
|
||||||
|
*number_data = std::stod(getUTF8StringFromString(string_data));
|
||||||
|
#endif // _WIN32
|
||||||
|
} catch (const std::logic_error& err) {
|
||||||
|
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103);
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_buffer_length = sizeof(double);
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLRETURN sqlsrv_buffered_result_set::string_to_long( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
SQLRETURN sqlsrv_buffered_result_set::string_to_long( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
||||||
|
@ -1181,7 +1109,16 @@ SQLRETURN sqlsrv_buffered_result_set::string_to_long( _In_ SQLSMALLINT field_ind
|
||||||
unsigned char* row = get_row();
|
unsigned char* row = get_row();
|
||||||
char* string_data = reinterpret_cast<char*>( &row[meta[field_index].offset] ) + sizeof( SQLULEN );
|
char* string_data = reinterpret_cast<char*>( &row[meta[field_index].offset] ) + sizeof( SQLULEN );
|
||||||
|
|
||||||
return string_to_number<LONG>( string_data, meta[field_index].length, buffer, buffer_length, out_buffer_length, last_error );
|
LONG* number_data = reinterpret_cast<LONG*>(buffer);
|
||||||
|
try {
|
||||||
|
*number_data = std::stol(std::string(string_data));
|
||||||
|
} catch (const std::logic_error& err) {
|
||||||
|
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103);
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_buffer_length = sizeof(LONG);
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLRETURN sqlsrv_buffered_result_set::wstring_to_long( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
SQLRETURN sqlsrv_buffered_result_set::wstring_to_long( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
||||||
|
@ -1193,7 +1130,20 @@ SQLRETURN sqlsrv_buffered_result_set::wstring_to_long( _In_ SQLSMALLINT field_in
|
||||||
unsigned char* row = get_row();
|
unsigned char* row = get_row();
|
||||||
SQLWCHAR* string_data = reinterpret_cast<SQLWCHAR*>( &row[meta[field_index].offset] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR );
|
SQLWCHAR* string_data = reinterpret_cast<SQLWCHAR*>( &row[meta[field_index].offset] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR );
|
||||||
|
|
||||||
return string_to_number<LONG>( string_data, meta[field_index].length, buffer, buffer_length, out_buffer_length, last_error );
|
LONG* number_data = reinterpret_cast<LONG*>(buffer);
|
||||||
|
try {
|
||||||
|
#ifdef _WIN32
|
||||||
|
*number_data = std::stol(std::wstring(string_data));
|
||||||
|
#else
|
||||||
|
*number_data = std::stol(getUTF8StringFromString(string_data));
|
||||||
|
#endif // _WIN32
|
||||||
|
} catch (const std::logic_error& err) {
|
||||||
|
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103);
|
||||||
|
return SQL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_buffer_length = sizeof(LONG);
|
||||||
|
return SQL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLRETURN sqlsrv_buffered_result_set::system_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
SQLRETURN sqlsrv_buffered_result_set::system_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
|
||||||
|
|
|
@ -14,6 +14,34 @@ $outOfRange = 'Numeric value out of range';
|
||||||
$truncation = 'Fractional truncation';
|
$truncation = 'Fractional truncation';
|
||||||
$epsilon = 0.00001;
|
$epsilon = 0.00001;
|
||||||
|
|
||||||
|
function fetchAsChar($conn, $tableName, $inputs)
|
||||||
|
{
|
||||||
|
$query = "SELECT c1, c2, c3, c4, c5, c6 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->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);
|
||||||
|
|
||||||
|
// Fetch all fields as strings - no conversion
|
||||||
|
for ($i = 0; $i < count($inputs) - 1; $i++) {
|
||||||
|
$stmt->execute();
|
||||||
|
$f = $stmt->fetchColumn($i);
|
||||||
|
|
||||||
|
if ($i == 2) {
|
||||||
|
if (!compareFloats(floatval($inputs[$i]), floatval($f))) {
|
||||||
|
echo "In fetchAsChar ($i): expected $inputs[$i]\n";
|
||||||
|
var_dump($f);
|
||||||
|
}
|
||||||
|
} elseif ($f !== $inputs[$i]) {
|
||||||
|
echo "In fetchAsChar ($i): expected $inputs[$i]\n";
|
||||||
|
var_dump($f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (PdoException $e) {
|
||||||
|
echo "Caught exception in fetchAsChar:\n";
|
||||||
|
echo $e->getMessage() . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fetchAsUTF8($conn, $tableName, $inputs)
|
function fetchAsUTF8($conn, $tableName, $inputs)
|
||||||
{
|
{
|
||||||
$query = "SELECT * FROM $tableName";
|
$query = "SELECT * FROM $tableName";
|
||||||
|
@ -145,14 +173,7 @@ function fetchCharAsInt($conn, $tableName, $column)
|
||||||
$stmt->bindColumn($column, $value, PDO::PARAM_INT);
|
$stmt->bindColumn($column, $value, PDO::PARAM_INT);
|
||||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||||
|
|
||||||
// TODO 11297: fix this part outside Windows later
|
echo "in fetchCharAsInt: exception should have been thrown!\n";
|
||||||
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) {
|
} catch (PdoException $e) {
|
||||||
// The (n)varchar field - expect the outOfRange error
|
// The (n)varchar field - expect the outOfRange error
|
||||||
if (strpos($e->getMessage(), $outOfRange) === false) {
|
if (strpos($e->getMessage(), $outOfRange) === false) {
|
||||||
|
@ -194,6 +215,35 @@ function fetchAsNumerics($conn, $tableName, $inputs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetchNumbers($conn, $tableName, $inputs)
|
||||||
|
{
|
||||||
|
// Fetch integers and floats as numbers, not strings
|
||||||
|
try {
|
||||||
|
$query = "SELECT c2, c3, 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->setAttribute(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, true);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_NUM);
|
||||||
|
if ($row[0] !== intval($inputs[1])) {
|
||||||
|
var_dump($row[0]);
|
||||||
|
}
|
||||||
|
$expected = floatval($inputs[2]);
|
||||||
|
if (!compareFloats($expected, $row[1])) {
|
||||||
|
echo "in fetchNumbers: expected $expected but got: ";
|
||||||
|
var_dump($row[1]);
|
||||||
|
}
|
||||||
|
if ($row[2] !== $inputs[3]) {
|
||||||
|
var_dump($row[2]);
|
||||||
|
}
|
||||||
|
} catch (PdoException $e) {
|
||||||
|
echo "Caught exception in fetchAsNumerics:\n";
|
||||||
|
echo $e->getMessage() . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$conn = connect();
|
$conn = connect();
|
||||||
$conn->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
|
$conn->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
|
||||||
|
@ -226,11 +276,13 @@ try {
|
||||||
unset($stmt);
|
unset($stmt);
|
||||||
|
|
||||||
// Starting fetching using client buffers
|
// Starting fetching using client buffers
|
||||||
|
fetchAsChar($conn, $tableName, $inputs);
|
||||||
fetchAsUTF8($conn, $tableName, $inputs);
|
fetchAsUTF8($conn, $tableName, $inputs);
|
||||||
fetchArray($conn, $tableName, $inputs);
|
fetchArray($conn, $tableName, $inputs);
|
||||||
fetchBinaryAsNumber($conn, $tableName, $inputs);
|
fetchBinaryAsNumber($conn, $tableName, $inputs);
|
||||||
fetchBinaryAsBinary($conn, $tableName, $inputs);
|
fetchBinaryAsBinary($conn, $tableName, $inputs);
|
||||||
fetchAsNumerics($conn, $tableName, $inputs);
|
fetchAsNumerics($conn, $tableName, $inputs);
|
||||||
|
fetchNumbers($conn, $tableName, $inputs);
|
||||||
|
|
||||||
// dropTable($conn, $tableName);
|
// dropTable($conn, $tableName);
|
||||||
echo "Done\n";
|
echo "Done\n";
|
||||||
|
|
|
@ -8,20 +8,17 @@ PHPT_EXEC=true
|
||||||
<?php
|
<?php
|
||||||
require_once("MsCommon_mid-refactor.inc");
|
require_once("MsCommon_mid-refactor.inc");
|
||||||
|
|
||||||
try {
|
function runTests($conn, $tableName, $buffered)
|
||||||
$conn1 = connect();
|
{
|
||||||
|
$tsql = "SELECT val FROM $tableName ORDER BY id";
|
||||||
// Prepare test table
|
$options = array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL);
|
||||||
$tableName = "pdo_test_table";
|
if ($buffered) {
|
||||||
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY", "none"), "val" => "varchar(10)"));
|
$options = array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED);
|
||||||
insertRow($conn1, $tableName, array("id" => 1, "val" => "A"));
|
}
|
||||||
insertRow($conn1, $tableName, array("id" => 2, "val" => "B"));
|
|
||||||
insertRow($conn1, $tableName, array("id" => 3, "val" => "C"));
|
|
||||||
|
|
||||||
// Query table and retrieve data
|
|
||||||
$stmt1 = $conn1->prepare( "SELECT val FROM $tableName ORDER BY id", array( PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL ));
|
|
||||||
|
|
||||||
|
$stmt1 = $conn->prepare($tsql, $options);
|
||||||
$stmt1->execute();
|
$stmt1->execute();
|
||||||
|
|
||||||
$row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST );
|
$row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST );
|
||||||
if( $row[ 'val' ] != "C" ) {
|
if( $row[ 'val' ] != "C" ) {
|
||||||
throw new Exception( "Not C" );
|
throw new Exception( "Not C" );
|
||||||
|
@ -149,9 +146,25 @@ try {
|
||||||
throw new Exception( "Not false" );
|
throw new Exception( "Not false" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unset($stmt1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$conn1 = connect();
|
||||||
|
|
||||||
|
// Prepare test table
|
||||||
|
$tableName = "pdo_test_table";
|
||||||
|
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY", "none"), "val" => "varchar(10)"));
|
||||||
|
insertRow($conn1, $tableName, array("id" => 1, "val" => "A"));
|
||||||
|
insertRow($conn1, $tableName, array("id" => 2, "val" => "B"));
|
||||||
|
insertRow($conn1, $tableName, array("id" => 3, "val" => "C"));
|
||||||
|
|
||||||
|
// Query table and retrieve data
|
||||||
|
runTests($conn1, $tableName, false);
|
||||||
|
runTests($conn1, $tableName, true);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
dropTable($conn1, $tableName);
|
dropTable($conn1, $tableName);
|
||||||
unset($stmt1);
|
|
||||||
unset($conn1);
|
unset($conn1);
|
||||||
|
|
||||||
echo "Test 'PDO Statement - Fetch Scrollable' completed successfully.\n";
|
echo "Test 'PDO Statement - Fetch Scrollable' completed successfully.\n";
|
||||||
|
|
|
@ -20,6 +20,41 @@ function compareFloats($expected, $actual)
|
||||||
return ($diff < $epsilon);
|
return ($diff < $epsilon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetchAsChar($conn, $tableName, $inputs)
|
||||||
|
{
|
||||||
|
$query = "SELECT c_varbinary, c_int, c_float, c_decimal, c_datetime2, c_varchar FROM $tableName";
|
||||||
|
|
||||||
|
$stmt = sqlsrv_query($conn, $query, array(), array("Scrollable"=>SQLSRV_CURSOR_CLIENT_BUFFERED));
|
||||||
|
if (!$stmt) {
|
||||||
|
fatalError("In fetchAsChar: failed to run query!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sqlsrv_fetch($stmt, SQLSRV_FETCH_NUMERIC) === false) {
|
||||||
|
fatalError("In fetchAsChar: failed to fetch the row from $tableName!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all fields as strings - no conversion
|
||||||
|
for ($i = 0; $i < count($inputs) - 1; $i++) {
|
||||||
|
$f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
|
||||||
|
if ($i == 0) {
|
||||||
|
if ($inputs[$i] !== hex2bin($f)) {
|
||||||
|
echo "In fetchAsChar ($i): expected $inputs[$i]\n";
|
||||||
|
var_dump(hex2bin($f));
|
||||||
|
}
|
||||||
|
} elseif ($i == 2) {
|
||||||
|
if (!compareFloats(floatval($inputs[$i]), floatval($f))) {
|
||||||
|
echo "In fetchAsChar ($i): expected $inputs[$i]\n";
|
||||||
|
var_dump($f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($f !== $inputs[$i]) {
|
||||||
|
echo "In fetchAsChar ($i): expected $inputs[$i]\n";
|
||||||
|
var_dump($f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fetchAsUTF8($conn, $tableName, $inputs)
|
function fetchAsUTF8($conn, $tableName, $inputs)
|
||||||
{
|
{
|
||||||
$query = "SELECT * FROM $tableName";
|
$query = "SELECT * FROM $tableName";
|
||||||
|
@ -132,16 +167,9 @@ function fetchAsFloats($conn, $tableName, $inputs)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The char fields will get errors too
|
// The char fields will get errors too
|
||||||
// TODO 11297: fix this part outside Windows later
|
if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) {
|
||||||
if (isWindows()) {
|
var_dump($f);
|
||||||
if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) {
|
fatalError("in fetchAsFloats: expected $outOfRange for column $i\n");
|
||||||
var_dump($f);
|
|
||||||
fatalError("in fetchAsFloats: expected $outOfRange for column $i\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($f != 0.0) {
|
|
||||||
var_dump($f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,16 +207,9 @@ function fetchAsInts($conn, $tableName, $inputs)
|
||||||
}
|
}
|
||||||
} elseif ($i >= 5) {
|
} elseif ($i >= 5) {
|
||||||
// The char fields will get errors too
|
// The char fields will get errors too
|
||||||
// TODO 11297: fix this part outside Windows later
|
if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) {
|
||||||
if (isWindows()) {
|
var_dump($f);
|
||||||
if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) {
|
fatalError("in fetchAsInts: expected $outOfRange for column $i\n");
|
||||||
var_dump($f);
|
|
||||||
fatalError("in fetchAsInts: expected $outOfRange for column $i\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($f != 0) {
|
|
||||||
var_dump($f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$expected = floor($inputs[$i]);
|
$expected = floor($inputs[$i]);
|
||||||
|
@ -284,6 +305,7 @@ if ($stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starting fetching using client buffers
|
// Starting fetching using client buffers
|
||||||
|
fetchAsChar($conn, $tableName, $inputs);
|
||||||
fetchAsUTF8($conn, $tableName, $inputs);
|
fetchAsUTF8($conn, $tableName, $inputs);
|
||||||
fetchArray($conn, $tableName, $inputs);
|
fetchArray($conn, $tableName, $inputs);
|
||||||
fetchAsFloats($conn, $tableName, $inputs);
|
fetchAsFloats($conn, $tableName, $inputs);
|
||||||
|
|
Loading…
Reference in a new issue