From fd750b5941b268e6f66a13a67f2af07809c1e2bd Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Wed, 12 Feb 2020 14:05:56 -0800 Subject: [PATCH 1/6] Removed the use of a conversion matrix --- source/shared/core_results.cpp | 101 ++++++++++++++++++++------------- source/shared/core_sqlsrv.h | 7 --- 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/source/shared/core_results.cpp b/source/shared/core_results.cpp index 0b9c8fd94..afa3bf56e 100644 --- a/source/shared/core_results.cpp +++ b/source/shared/core_results.cpp @@ -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_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, diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index ae27400e8..d576993d9 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -1746,13 +1746,6 @@ struct sqlsrv_buffered_result_set : public sqlsrv_result_set { sqlsrv_malloc_auto_ptr 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 ); From 6ca3b7645a9eb85fe52f6e4522376aa4d8ab3a86 Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Thu, 13 Feb 2020 14:09:07 -0800 Subject: [PATCH 2/6] Added a new sqlsrv test --- source/shared/core_stmt.cpp | 6 +- .../sqlsrv/sqlsrv_buffered_fetch_types.phpt | 321 ++++++++++++++++++ 2 files changed, 324 insertions(+), 3 deletions(-) create mode 100644 test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 32b10ad58..7fac8e5b3 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -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 field_value_temp; - field_value_temp = static_cast( sqlsrv_malloc( sizeof( long ))); + sqlsrv_malloc_auto_ptr field_value_temp; + field_value_temp = static_cast( 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 ) { diff --git a/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt b/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt new file mode 100644 index 000000000..70bd161e0 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt @@ -0,0 +1,321 @@ +--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-- + +--FILE-- +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, SQLSRV_FETCH_ASSOC); + if ($results === false) { + fatalError("In fetchArray: failed to fetch the row from $tableName!"); + } + + var_dump($results); +} + +function fetchAsFloats($conn, $tableName, $inputs) +{ + $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 ($f == false) { + print_r(sqlsrv_errors()); + } else { + var_dump($f); + } + } +} + +function fetchAsInts($conn, $tableName, $inputs) +{ + $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 ($f == false) { + print_r(sqlsrv_errors()); + } else { + var_dump($f); + } + } +} + +function fetchAsBinary($conn, $tableName, $inputs) +{ + $query = "SELECT c_varbinary, c_varchar, c_nvarchar 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 all fields as varbinary + for ($i = 0; $i < 3; $i++) { + $f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_STREAM("binary")); + if (gettype($f) !== 'resource') { + var_dump($f); + } + // Do not expect errors + $errs = sqlsrv_errors(); + if (!empty($errs)) { + var_dump($errs); + } + + // Checks the first field only for this test + while (!feof($f)) { + $str = fread($f, 80); + } + if ($i == 0) { + if (trim($str) !== $inputs[0]) { + echo "Fetched binary value unexpected: $str\n"; + } + } else { + print(bin2hex($str)); + } + } +} + +require_once('MsCommon.inc'); + +$conn = AE\connect(array('CharacterSet' => 'UTF-8')); +$tableName = 'testFetchingClientBuffer'; + +// 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); + +sqlsrv_free_stmt($stmt); +sqlsrv_close($conn); + +?> +--EXPECT-- +array(7) { + ["c_varbinary"]=> + string(10) "abcdefghij" + ["c_int"]=> + int(34567) + ["c_float"]=> + float(9876.5432) + ["c_decimal"]=> + string(16) "123456789.012340" + ["c_datetime2"]=> + string(27) "2020-02-02 20:20:20.2220000" + ["c_varchar"]=> + string(14) "This is a test" + ["c_nvarchar"]=> + string(23) "Şơмė śäოрŀề" +} +Array +( + [0] => Array + ( + [0] => 07006 + [SQLSTATE] => 07006 + [1] => 0 + [code] => 0 + [2] => Restricted data type attribute violation + [message] => Restricted data type attribute violation + ) + +) +float(34567) +float(9876.5432) +float(123456789.01234) +float(2020) +Array +( + [0] => Array + ( + [0] => 22003 + [SQLSTATE] => 22003 + [1] => 103 + [code] => 103 + [2] => Numeric value out of range + [message] => Numeric value out of range + ) + +) +Array +( + [0] => Array + ( + [0] => 22003 + [SQLSTATE] => 22003 + [1] => 103 + [code] => 103 + [2] => Numeric value out of range + [message] => Numeric value out of range + ) + +) +Array +( + [0] => Array + ( + [0] => 07006 + [SQLSTATE] => 07006 + [1] => 0 + [code] => 0 + [2] => Restricted data type attribute violation + [message] => Restricted data type attribute violation + ) + +) +int(34567) +Array +( + [0] => Array + ( + [0] => 01S07 + [SQLSTATE] => 01S07 + [1] => 0 + [code] => 0 + [2] => Fractional truncation + [message] => Fractional truncation + ) + +) +int(123456789) +int(2020) +Array +( + [0] => Array + ( + [0] => 22003 + [SQLSTATE] => 22003 + [1] => 103 + [code] => 103 + [2] => Numeric value out of range + [message] => Numeric value out of range + ) + +) +Array +( + [0] => Array + ( + [0] => 22003 + [SQLSTATE] => 22003 + [1] => 103 + [code] => 103 + [2] => Numeric value out of range + [message] => Numeric value out of range + ) + +) From cab529987ef5b12bee99312f4bac333704b8d885 Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Thu, 13 Feb 2020 16:23:03 -0800 Subject: [PATCH 3/6] Made the new test more robust --- .../sqlsrv/sqlsrv_buffered_fetch_types.phpt | 599 ++++++++---------- 1 file changed, 278 insertions(+), 321 deletions(-) diff --git a/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt b/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt index 70bd161e0..3d0cdb59d 100644 --- a/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt +++ b/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt @@ -1,321 +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-- - ---FILE-- -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, SQLSRV_FETCH_ASSOC); - if ($results === false) { - fatalError("In fetchArray: failed to fetch the row from $tableName!"); - } - - var_dump($results); -} - -function fetchAsFloats($conn, $tableName, $inputs) -{ - $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 ($f == false) { - print_r(sqlsrv_errors()); - } else { - var_dump($f); - } - } -} - -function fetchAsInts($conn, $tableName, $inputs) -{ - $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 ($f == false) { - print_r(sqlsrv_errors()); - } else { - var_dump($f); - } - } -} - -function fetchAsBinary($conn, $tableName, $inputs) -{ - $query = "SELECT c_varbinary, c_varchar, c_nvarchar 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 all fields as varbinary - for ($i = 0; $i < 3; $i++) { - $f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_STREAM("binary")); - if (gettype($f) !== 'resource') { - var_dump($f); - } - // Do not expect errors - $errs = sqlsrv_errors(); - if (!empty($errs)) { - var_dump($errs); - } - - // Checks the first field only for this test - while (!feof($f)) { - $str = fread($f, 80); - } - if ($i == 0) { - if (trim($str) !== $inputs[0]) { - echo "Fetched binary value unexpected: $str\n"; - } - } else { - print(bin2hex($str)); - } - } -} - -require_once('MsCommon.inc'); - -$conn = AE\connect(array('CharacterSet' => 'UTF-8')); -$tableName = 'testFetchingClientBuffer'; - -// 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); - -sqlsrv_free_stmt($stmt); -sqlsrv_close($conn); - -?> ---EXPECT-- -array(7) { - ["c_varbinary"]=> - string(10) "abcdefghij" - ["c_int"]=> - int(34567) - ["c_float"]=> - float(9876.5432) - ["c_decimal"]=> - string(16) "123456789.012340" - ["c_datetime2"]=> - string(27) "2020-02-02 20:20:20.2220000" - ["c_varchar"]=> - string(14) "This is a test" - ["c_nvarchar"]=> - string(23) "Şơмė śäოрŀề" -} -Array -( - [0] => Array - ( - [0] => 07006 - [SQLSTATE] => 07006 - [1] => 0 - [code] => 0 - [2] => Restricted data type attribute violation - [message] => Restricted data type attribute violation - ) - -) -float(34567) -float(9876.5432) -float(123456789.01234) -float(2020) -Array -( - [0] => Array - ( - [0] => 22003 - [SQLSTATE] => 22003 - [1] => 103 - [code] => 103 - [2] => Numeric value out of range - [message] => Numeric value out of range - ) - -) -Array -( - [0] => Array - ( - [0] => 22003 - [SQLSTATE] => 22003 - [1] => 103 - [code] => 103 - [2] => Numeric value out of range - [message] => Numeric value out of range - ) - -) -Array -( - [0] => Array - ( - [0] => 07006 - [SQLSTATE] => 07006 - [1] => 0 - [code] => 0 - [2] => Restricted data type attribute violation - [message] => Restricted data type attribute violation - ) - -) -int(34567) -Array -( - [0] => Array - ( - [0] => 01S07 - [SQLSTATE] => 01S07 - [1] => 0 - [code] => 0 - [2] => Fractional truncation - [message] => Fractional truncation - ) - -) -int(123456789) -int(2020) -Array -( - [0] => Array - ( - [0] => 22003 - [SQLSTATE] => 22003 - [1] => 103 - [code] => 103 - [2] => Numeric value out of range - [message] => Numeric value out of range - ) - -) -Array -( - [0] => Array - ( - [0] => 22003 - [SQLSTATE] => 22003 - [1] => 103 - [code] => 103 - [2] => Numeric value out of range - [message] => Numeric value out of range - ) - -) +--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-- + +--FILE-- +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: 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: 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 = 'testFetchingClientBuffer'; + +// 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 From a230add91702eade3d2354d04e3abf7c136da59d Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Fri, 14 Feb 2020 13:29:34 -0800 Subject: [PATCH 4/6] Added an equivalent pdo test --- .../pdo_sqlsrv/pdo_buffered_fetch_types.phpt | 229 ++++++++++++++++++ .../sqlsrv/sqlsrv_buffered_fetch_types.phpt | 6 +- 2 files changed, 232 insertions(+), 3 deletions(-) create mode 100644 test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt diff --git a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt new file mode 100644 index 000000000..32801b55d --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt @@ -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-- + +--FILE-- +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 fetchFloat:\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 (isWindows()) { + 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 \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt b/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt index 3d0cdb59d..425d7f58f 100644 --- a/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt +++ b/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt @@ -108,7 +108,7 @@ function fetchAsFloats($conn, $tableName, $inputs) } } else { // The char fields will get errors too - // TODO: fix this part outside Windows later + // TODO 11297: fix this part outside Windows later if (isWindows()) { if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) { var_dump($f); @@ -155,7 +155,7 @@ function fetchAsInts($conn, $tableName, $inputs) } } elseif ($i >= 5) { // The char fields will get errors too - // TODO: fix this part outside Windows later + // TODO 11297: fix this part outside Windows later if (isWindows()) { if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) { var_dump($f); @@ -216,7 +216,7 @@ function fetchAsBinary($conn, $tableName, $inputs) require_once('MsCommon.inc'); $conn = AE\connect(array('CharacterSet' => 'UTF-8')); -$tableName = 'testFetchingClientBuffer'; +$tableName = 'srvFetchingClientBuffer'; // Create table $names = array('c_varbinary', 'c_int', 'c_float', 'c_decimal', 'c_datetime2', 'c_varchar', 'c_nvarchar'); From 17c3343a344850c797eda580a4fc32d109c31ef7 Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Fri, 14 Feb 2020 14:13:08 -0800 Subject: [PATCH 5/6] Fixed the error --- test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt index 32801b55d..e2ecf16b9 100644 --- a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt +++ b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt @@ -132,7 +132,7 @@ function fetchCharAsInt($conn, $tableName, $column) $row = $stmt->fetch(PDO::FETCH_BOUND); // TODO 11297: fix this part outside Windows later - if (isWindows()) { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { echo "in fetchCharAsInt: exception should have been thrown!\n"; } else { if ($value != 0) { From 5523c54adc427877c2dc1be81a63d5403477011b Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Wed, 19 Feb 2020 10:53:37 -0800 Subject: [PATCH 6/6] Fixed a mistake in a comment as per review --- test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt index e2ecf16b9..a10bf6c38 100644 --- a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt +++ b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt @@ -114,7 +114,7 @@ function fetchFloatAsInt($conn, $tableName) print_r($stmt->errorInfo()); } } catch (PdoException $e) { - echo "Caught exception in fetchFloat:\n"; + echo "Caught exception in fetchFloatAsInt:\n"; echo $e->getMessage() . PHP_EOL; } }